Обработка текста с использованием awk, когда разделитель является частью слова? [дубликат]

avatar
Maryam Pashmi
8 апреля 2018 в 11:32
108
1
0

У меня есть файл CSV, содержащий 11 столбцов с похожим содержимым

 SE Australia|PRM|2017-09-07T16:11:33|2641|-5537383165259899960|2017-09-07T16:12:17|"AU en2|networking-locator"|-|SC7_Electricians_Installer (only provides labor)|p-0715125|1

Я пытаюсь использовать awk для разделения каждого столбца. Проблема в том, что в некоторых предложениях среди 10 миллионов записей разделитель (пункт) является частью слова. Как вы можете видеть ниже, пункт включен в текст "AU en2|networking-locator". Использование следующей команды возвращает неверную информацию.

awk -F "|" '{print $4"_"$6"_"$7"_"$10}'

Результат

2641_2017-09-07T16:12:17_"AU en2_p-0715125

Исключенный результат,

2641_2017-09-07T16:12:17_"AU en2|networking-locator"_p-0715125

Как видите, AU en2 рассматривается как отдельный столбец, однако является частью AU en2|networking-locator. Как я могу изменить команду awk, чтобы охватить эти столбцы?

Источник
RavinderSingh13
8 апреля 2018 в 11:42
0

Ваш образец ввода и образец вывода НЕ понятен? Пожалуйста, разместите их более четко с тегами CODE и дайте мне знать.

Maryam Pashmi
8 апреля 2018 в 11:47
0

@ RavinderSingh13 Я разъясняю.

RavinderSingh13
8 апреля 2018 в 11:53
0

Пожалуйста, проверьте мой код сейчас и дайте мне знать, поможет ли это вам?

Maryam Pashmi
8 апреля 2018 в 14:43
1

@EdMorton, это была ошибка, я отредактировал. Прости.

Ответы (1)

avatar
hek2mgl
8 апреля 2018 в 11:57
2

Для этого вам понадобится GNU awk. С gawk вы можете использовать переменную FPAT:

gawk '{print $4,$6,$7,$10}' OFS=_ FPAT='"[^"]+"|[^|]+' file

Используя FPAT, вы можете сообщить awk, как выглядит поле, вместо того, чтобы ограничиваться указанием разделителя полей.

В приведенном выше примере мы говорим, что поле представляет собой либо ", за которым следует один или несколько символов, отличных от ", и закрывающий " или char10, не равный <907136 . Эти правила будут оцениваться в том порядке, в котором первое имеет более высокий приоритет.

Вывод:

2641_2017-09-07T16:12:17_"AU en2|networking-locator"_p-0715125

PS: Приведенное выше решение медленнее, чем разбиение на фиксированный символ. Поскольку ваш файл состоит из 100 миллионов строк, его обработка может занять очень много времени.

Если файл содержит поля "abc|xyz" только в позиции $7 и, можно с уверенностью сказать, что в этих ситуациях есть только один | в $7, то вы можете использовать этот хак:

awk -F\| '$7~/"/{$7=$7"|"$8;$10=$11}{print $4,$6,$7,$10}' OFS=_ file

Это должно быть намного быстрее, чем приведенное выше решение, но оно работает только при указанных обстоятельствах. Вас предупредили!.

Maryam Pashmi
8 апреля 2018 в 12:22
0

Выглядит неуклюже, используя этот параметр, работает очень медленно с огромным объемом данных. Я запустил команду 20 минут назад и все еще работает. с awk тот же файл будет обработан за 3 минуты.

hek2mgl
8 апреля 2018 в 12:30
0

Конечно, для разделения на сложное регулярное выражение требуется больше усилий, чем для разделения на фиксированный char. Вам придется подождать (независимо от языка программирования, который вы используете, а awk уже довольно быстр). Если вы можете изменить процесс, убедитесь, что вы используете разделитель полей, который не является частью данных.

hek2mgl
8 апреля 2018 в 12:46
0

@MaryamPashmi Я добавил более быстрое решение. Но, пожалуйста, проверьте требования к нему.

Ed Morton
8 апреля 2018 в 13:12
1

Первый может быть немного быстрее, если вы установите OFS и будете использовать запятые между полями вывода, а не использовать конкатенацию строк (медленная операция) с жестко запрограммированными символами подчеркивания.

hek2mgl
8 апреля 2018 в 21:06
0

Хорошая точка зрения! Измененный...