Вопрос или проблема
У нас есть требование нормализовать данные … Поле элемента разделено запятыми и нерегулярно, и оно может содержать элементы от 0 до максимума (скажем, 100)
Входные данные:
key1|desc field|item1,item2,item3,item4|extra field
key2|desc field|item1,item2,item3|extra field
Выходные данные:
key1|desc field|item1|extra field
key1|desc field|item2|extra field
key1|desc field|item3|extra field
key1|desc field|item4|extra field
key2|desc field|item1|extra field
key2|desc field|item2|extra field
key2|desc field|item3|extra field
Существует ли способ, которым мы можем это достичь с помощью команды Unix или shell-скрипта? Пожалуйста, дайте совет.
Используя Miller (mlr
) для “взрыва” подполей, разделённых запятыми, третьего поля во вводе, разделенном трубами:
$ mlr --nidx --fs pipe nest --evar , -f 3 file
key1|desc field|item1|extra field
key1|desc field|item2|extra field
key1|desc field|item3|extra field
key1|desc field|item4|extra field
key2|desc field|item1|extra field
key2|desc field|item2|extra field
key2|desc field|item3|extra field
Вот подход на Perl, который предполагает, что у вас никогда не будет |
внутри каких-либо элементов:
$ perl -F'\|' -ane '@items = split(/,/,$F[2]); print join("|",@F[0,1],$_,@F[3..$#F]) for @items' file
key1|desc field|item1|extra field
key1|desc field|item2|extra field
key1|desc field|item3|extra field
key1|desc field|item4|extra field
key2|desc field|item1|extra field
key2|desc field|item2|extra field
key2|desc field|item3|extra field
Флаг -n
говорит perl
читать входные данные построчно и применять скрипт, указанный следующей командой -e
, к каждой строке. Флаг -a
говорит perl
вести себя как awk
и разбивать входные данные по символу, указанному в -F
, и сохранять результат в массив @F
.
Затем в скрипте мы разбиваем третье поле (нумерация начинается с 0, так что $F[2]
— это третье поле) по запятым и сохраняем результат в массив @items
. Затем для каждого элемента массива @items
мы печатаем результат объединения первых двух полей с |
(что дает нам начало оригинальной входной строки), затем текущий элемент (значение специальной переменной $_
), и затем оставшуюся часть массива. Все объединяется с помощью |
.
Вот очень короткое решение на python3; поместите его в файл (например, normalize.py
), сделайте его исполняемым (chmod 755 normalize.py
) и запустите его на своих входных данных (./normalize.py < your_input_data.file
)
#!/usr/bin/env python3
from sys import stdin
for line in stdin:
key, desc, items, extra = line.split("|")
for item in items.split(","):
if item:
print(f"{key}|{desc}|{item}|{extra}")
Предположения: везде нет |
, кроме как для разделителей столбцов, ровно 4 столбца на входную строку и в списке элементов нет запятых, кроме тех, которые разделяют элементы.
Обратите внимание, что ваш вопрос в основном кричит о том, что вам, вероятно, нужен лучший реляционный модель данных, чем это; в классическом дизайне реляционной базы данных вы бы создали две таблицы из этого:
- таблица “itemtypes” со столбцами ‘key’ (уникальный, первичный ключ), ‘description’ и ‘extra’
- таблица “items” со столбцом ‘item’ и столбцом ‘type_key’, который ссылается на ‘itemtypes.key’.
Используя awk:
awk -F'|' '
{
split($3, items, ",");
for (i=1; i in items; i++)
print $1 "|" $2 "|" items[i] "|" $4
}'
Это разобьет 3-й столбец на массив с именем items
, разделенный ,
. Для каждого элемента в items он напечатает новую строку, используя значение каждого другого столбца из исходной строки.
Используя любой awk:
$ cat tst.awk
BEGIN { FS=OFS="|" }
{
n = split($3, f, ",")
for ( i=1; i<=n; i++ ) {
$3 = f[i]
print
}
}
$ awk -f tst.awk file
key1|desc field|item1|extra field
key1|desc field|item2|extra field
key1|desc field|item3|extra field
key1|desc field|item4|extra field
key2|desc field|item1|extra field
key2|desc field|item2|extra field
key2|desc field|item3|extra field
Ответ или решение
Скрипт Shell для нормализации данных
Вопрос, связанный с нормализацией данных, представляет собой задачу, требующую преобразования входного формата строки, где третье поле отделено запятыми, в более структурированный и удобный для обработки вид. В данной статье мы рассмотрим несколько подходов к решению этой задачи с использованием различных языков программирования и инструментов командной строки.
1. Структура входных и выходных данных
Входные данные содержат строки с полями, разделенными символом |
, где третье поле содержит элементы, разделенные запятыми:
Вход:
key1|desc field|item1,item2,item3,item4|extra field
key2|desc field|item1,item2,item3|extra field
Выход:
key1|desc field|item1|extra field
key1|desc field|item2|extra field
key1|desc field|item3|extra field
key1|desc field|item4|extra field
key2|desc field|item1|extra field
key2|desc field|item2|extra field
key2|desc field|item3|extra field
2. Решение с помощью awk
awk
— это мощный инструмент для обработки текстовых файлов. Вот пример использования awk
для достижения желаемого результата:
awk -F'|' '
{
split($3, items, ","); # Разделяем третье поле на массив items
for (i = 1; i <= length(items); i++)
print $1 "|" $2 "|" items[i] "|" $4 # Выводим нужные поля
}' input_file
3. Решение с использованием Perl
Perl предоставляет мощные средства для работы с текстом. Пример решения на Perl:
perl -F'\|' -ane '@items = split(/,/,$F[2]); for (@items) { print join("|", $F[0], $F[1], $_, $F[3]), "\n" }' input_file
4. Использование Python
Python — еще один популярный инструмент для обработки данных. Вот как можно реализовать задачу на Python:
#!/usr/bin/env python3
from sys import stdin
for line in stdin:
key, desc, items, extra = line.strip().split("|")
for item in items.split(","):
if item: # Проверяем, что элемент не пустой
print(f"{key}|{desc}|{item}|{extra}")
Сохраните этот код в файл, сделайте его исполняемым и запустите.
5. Использование Miller (mlr
)
mlr
— это инструмент для обработки и преобразования данных, который можно использовать следующим образом:
mlr --nidx --fs pipe nest --evar , -f 3 input_file
Заключение
В данной статье мы рассмотрели различные подходы к нормализации данных в формате, где поля разделены символами |
и третье поле содержит элементы, разделенные запятыми. Вы можете выбрать любой из предложенных методов в зависимости от ваших предпочтений и условий. Инструменты, такие как awk
, Perl, Python и Miller, предоставляют эффективные решения для решения данной задачи.
Для полноценной работы с данными рекомендуется рассмотреть возможность более строгой модели данных, например, использования реляционных баз данных, где данные могут быть структурированы более логично и эффективно.