Вопрос или проблема
У меня есть файл, разделенный табуляцией, где один из столбцов имеет формат “Фамилия, Имя”. Я хотел бы разделить эту запись на два отдельных столбца, фамилия
и имя
, использовать cut
или какие-то другие команды для этого и вывести результат в формате JSON.
Я должен добавить, что не привязан к JSON, и я знаю, как использовать другие инструменты, такие как jq
, но было бы неплохо получить это в таком формате за один шаг.
Синтаксис для глагола nest
выглядит так, будто необходимо запомнить множество, честно говоря, не запоминающихся опций, поэтому мне показалось, что должна быть простая DSL операция для выполнения этой задачи. Может быть, это не так?
Вот что я пробовал. (Давайте просто забудем о лишнем пробеле, который прикреплен к Имя
прямо сейчас, ладно? Я бы использовал strip
или ssub
или что-то подобное, чтобы избавиться от него позже.)
echo -e "last_first\nLastName, Firstname" \
| mlr --t2j put '$o=splitnv($last_first,",")'
# результат:
# { "last_first": "LastName, Firstname", "o": "(ошибка)" }
# ожидалось что-то вроде:
# { "last_first": "LastName, Firstname", "o": { 1: "LastName", 2: "Firstname" } }
#
# или:
# { "last_first": "LastName, Firstname", "o": [ "LastName", "Firstname" ] }
Почему (ошибка)
? Не разумно ли полагать, что назначение $o
, как указано выше, присвоит новую колонку o
результату splitnv
?
Вот что-то еще, что я пробовал, но тоже не сработало, как я ожидал:
echo -e "last_first\nLastName, Firstname" \
| mlr -T nest --explode --values --across-fields --nested-fs , -f last_first
# результат (без разделителя здесь, только одно поле, подтверждено с помощью 'cat -A')
# last_first
# LastName, Firstname
# ожидалось:
# last_first_1<tab>last_first_2
# LastName,<tab> Firstname
Редактирование: Проблема с командой выше в том, что я должен был использовать --tsv
, а не -T
, что является синонимом --nidx --fs tab
(числовых индексов столбцов). Проблема в том, что Miller не выдает сообщение об ошибке, когда явно неправильно запрашивать именованные столбцы в этом случае, что может быть недостатком; см. вопрос #233.
Любая информация будет принята с благодарностью.
Я не знаю, правильно ли я понимаю ваш запрос.
Если я выполняю
echo -e "last_first\nLastName, Firstname" | \
mlr --t2j --jlistwrap --jvstack nest --explode --values --across-fields --nested-fs "," -f last_first \
then clean-whitespace
У меня получается
[
{
"last_first_1": "LastName",
"last_first_2": "Firstname"
}
]
И если я выполняю
echo -e "last_first\nLastName, Firstname" | \
mlr --tsv nest --explode --values --across-fields --nested-fs "," -f last_first \
then clean-whitespace
Я получаю
last_first_1 last_first_2
LastName Firstname
Вот как переключить LastName, FirstName
на FirstName LastName
с помощью выражений DSL:
echo -e "last_first\nLastName, Firstname\nAnotherLast, AnotherFirst" \
| mlr --t2j \
put -q 'o=splitnv($last_first,",");
first_last=strip(o[2]) . " " . o[1];
emit first_last'
# результат:
# { "first_last": "Firstname LastName" }
# { "first_last": "AnotherFirst AnotherLast" }
Я думаю, что факт, что emit
оказывается необходимым(?), был ключевой частью, которую я не понимал раньше.
К сожалению, это не намного проще, чем использование глагола nest
и всех его необходимых флагов.
С более актуальной версией Miller, ваша команда mlr --t2j put '$o=splitnv($last_first,",")'
генерирует
[
{
"last_first": "LastName, Firstname",
"o": {
"1": "LastName",
"2": " Firstname"
}
}
]
… в то время как использование splita()
генерировало бы
[
{
"last_first": "LastName, Firstname",
"o": ["LastName", " Firstname"]
}
]
Предполагая, что поле last_first
всегда содержит одну запятую…
С
put '$last_first = splita($last_first,",")'
… мы заменяем данное строковое поле last_first
на массив, содержащий начальные пробелы во втором элементе:
+--------------+--------------+
| last_first.1 | last_first.2 |
+--------------+--------------+
| LastName | Firstname |
+--------------+--------------+
Мы можем flatten
этот массив и использовать clean-whitespace
, чтобы избавиться от пробелов:
put '$last_first = splita($last_first,",") then \
flatten then \
clean-whitespace
Чтобы получить результат, переименуйте поля:
put '$last_first = splita($last_first,",")' then \
flatten then \
clean-whitespace then \
label last,first
Это дает нам
+----------+-----------+
| last | first |
+----------+-----------+
| LastName | Firstname |
+----------+-----------+
Ответ или решение
Чтобы решить проблему, описанную вами, необходимо использовать инструмент Miller (mlr) для изменения формата данных в табличном файле, где одно из полей формата "LastName, FirstName"
. Задача заключается в том, чтобы разделить это поле на два отдельных столбца last
и first
, а затем экспортировать результат в JSON-формате. Давайте рассмотрим подход к решению этой задачи более детально, следуя методу TEA (Теория, Пример, Применение).
Теория
Miller (mlr) – это мощный инструмент командной строки, который позволяет обрабатывать данные из файлов в формате CSV, JSON и многих других. Он известен своей способностью быстро и эффективно обрабатывать данные и предоставлять возможности для выполнения различных трансформаций и анализов.
Для вашей задачи нам нужно использовать функцию split
для разделения строки по определенному разделителю (в данном случае – запятая) и манипулировать данными так, чтобы получить нужный вывод. Специфика системы Miller позволяет нам использовать сценарии на встроенном языке для выполнения более сложных операций с данными.
Пример
Прежде чем мы перейдем к тому, как применять это на практике, приведем пример выполнения этих шагов:
-
Входные данные:
last_first LastName, Firstname
-
Способ применения:
Вы можете использовать следующее сочетание команд Miller для достижения цели разделения имени и фамилии:
echo -e "last_first\nLastName, Firstname" \ | mlr --t2j put '$last_first = splita($last_first, ",")' then \ flatten then \ clean-whitespace then \ label last, first
-
Результат формата JSON:
Для вывода в формате JSON, вы можете выполнить:
echo -e "last_first\nLastName, Firstname" \ | mlr --t2j --jlistwrap --jvstack put '$last_first = splita($last_first, ",")' then \ flatten then \ clean-whitespace then \ label last, first
Это создаст JSON-вывод следующего вида:
[ { "last": "LastName", "first": "Firstname" } ]
Применение
Понимание синтаксиса и как применять функции в Miller является ключевым моментом для выполнения этой задачи. Использование команд splita
и flatten
в совместимости с другими утилитами Miller позволяют эффективно разделить и обработать текстовые строки.
-
Функция
splita
: Она используется для разделения строки на массив, основываясь на заданном разделителе. Это полезно, когда нам нужно разделить имени и фамилии, используя запятую в качестве разделителя. -
Функция
flatten
: После разделения строки мы получаем массив, который нужно преобразовать обратно в простые столбцы для дальнейшей обработки. -
Функция
clean-whitespace
: Она устраняет лишние пробелы в строках, которые могли быть оставлены после операции разделения. -
Команда
label
: Позволяет нам переименовать полученные поля массива в более понятныеlast
иfirst
.
Следуя этим шагам, можно настроить обработку даже более сложных наборов данных, расширяя использование Miller для различных форма🔥тов данных и более сложных трансформаций. Например, вы можете настроить вывод на работу с другими формами экспорта или добавлять дополнительные этапы обработки данных, такие как фильтрация или агрегирование информации по специфическим требованиям вашего рабочего процесса.
Для выполнения операции преобразования полей в формат FirstName LastName
, вы можете использовать следующий подход:
echo -e "last_first\nLastName, Firstname" \
| mlr --t2j \
put 'o=splitnv($last_first,",");
first_last=strip(o[2]) . " " . o[1];
emit first_last'
Данный подход не только показывает гибкость и универсальность Miller, но и позволяет легко адаптировать его под различные форматы и требования к итоговому результату.