Экранирование разделителя в двойных кавычках в awk

Я использую awk для анализа своих данных с помощью «,» в качестве разделителя, поскольку вход представляет собой файл csv. Однако в данных есть ",", которые заключены в двойные кавычки ("...").

Пример

filed1,filed2,field3,"field4,FOO,BAR",field5

Как я могу игнорировать запятую "," в двойной кавычке, чтобы правильно анализировать вывод с помощью awk? Я знаю, что мы можем сделать это в Excel, но как это сделать в awk?


person joomanji    schedule 18.10.2011    source источник
comment
Подробное описание смотрите здесь: ›http://web.archive.org/web/20120531065332/http://backreference.org/2010/04/17/csv-parsing-with-awk/ (версия из архива.org) Но это не парсинг, а читерство с regexp . Для чего-то более сложного, чем примеры на странице, вы должны использовать Perl/Python с библиотекой парсера, такой как csv для Python.   -  person Chris    schedule 18.10.2011
comment
Отличные статьи о парсинге Text:CSV с использованием perl: perlmeme.org/tutorials/parsing_csv.html   -  person joomanji    schedule 18.10.2011
comment
См. stackoverflow.com/q/45420535/1745001 для синтаксического анализа CSV с помощью awk.   -  person Ed Morton    schedule 27.09.2017


Ответы (3)


С GNU awk 4 это просто:

zsh-4.3.12[t]% awk '{ 
 for (i = 0; ++i <= NF;)
   printf "field %d => %s\n", i, $i
 }' FPAT='([^,]+)|("[^"]+")' infile
field 1 => filed1
field 2 => filed2
field 3 => field3
field 4 => "field4,FOO,BAR"
field 5 => field5

Добавление некоторых комментариев в соответствии с требованием ОП.

Из руководства GNU awk по "Определение полей по содержимому:

Значение FPAT должно быть строкой, содержащей регулярное выражение. Это регулярное выражение описывает содержимое каждого поля. В случае данных CSV, представленных выше, каждое поле представляет собой либо «все, что не является запятой», либо «двойную кавычку, все, что не является двойной кавычкой, и закрывающую двойную кавычку». Если бы она была записана как константа регулярного выражения, у нас было бы /([^,]+)|("[^"]+")/. Запись этого в виде строки требует от нас избежать двойных кавычек, что приводит к:

FPAT = "([^,]+)|(\"[^\"]+\")"

Используя + дважды, это не работает должным образом для пустых полей, но это также можно исправить:

Как написано, регулярное выражение, используемое для FPAT, требует, чтобы каждое поле содержало хотя бы один символ. Прямая модификация (изменение первого «+» на «*») позволяет полям быть пустыми:

FPAT = "([^,]*)|(\"[^\"]+\")"

person Dimitre Radoulov    schedule 18.10.2011
comment
Это блестяще @DimitreRadoulov. Вы очень хорошо знаете gawk :-). Я использовал ваше предложение по здесь и сделал ссылку на этот ответ. Надеюсь, это нормально. +1 - person jaypal singh; 21.01.2012
comment
Переходя от здесь, это решение не работает для моих данных. На самом деле он разбивает поля на основе пробелов (значение FS по умолчанию — пробел), а не регулярного выражения, указанного FPAT. Добавление FS=",", по-видимому, заставляет awk полностью игнорировать FPAT, поскольку оно не экранирует поле в кавычках со встроенной запятой. - person chrisbunney; 23.01.2012
comment
Привет @chrisbunney, не могли бы вы подтвердить, что используете GNU awk 4? Зачем ты ставишь ФС? - person Dimitre Radoulov; 23.01.2012
comment
Очевидно, я не использую GNU awk 4: gawk -W version: GNU Awk 3.1.7. Хотя вы указали GNU awk 4, я не знал, что эта функциональность может отсутствовать в более ранних версиях. Я возился, поэтому я поставил FS, чтобы посмотреть, что произошло. - person chrisbunney; 23.01.2012
comment
Встроенная переменная FPAT появилась в GNU awk 4. Я только что опубликовал решение Perl в вашей исходной теме. - person Dimitre Radoulov; 23.01.2012
comment
Пользователи Mac могут сделать brew install gawk и использовать gawk вместо awk. - person scottgwald; 04.03.2016
comment
Это решение работает для mawk? Я пробовал в gawk, и он работает, но не работает в mawk. - person Data Origin; 13.08.2019

FPAT работает, когда внутри полей в кавычках есть символы новой строки и запятые, но не когда есть двойные кавычки, например:

field1,"field,2","but this field has ""escaped"" quotes"

Вы можете использовать простую программу-оболочку, которую я написал, под названием csvquote, чтобы упростить интерпретацию данных для awk, а затем восстановить проблемные специальные символы, например:

csvquote inputfile.csv | awk -F, '{print $4}' | csvquote -u

Код и документы см. на странице https://github.com/dbro/csvquote.

person D Bro    schedule 04.05.2013
comment
Привет, @DBro Двойные двойные кавычки можно объяснить небольшим расширением регулярного выражения FPAT: BEGIN { FPAT = "(\"([^\"]|\"\")*\")|([^,\"]*)" } - person colemar; 11.03.2016

Полноценные синтаксические анализаторы CSV, такие как Text::CSV_XS в Perl, специально созданы для обработки такого рода странностей.

Предположим, вы хотите напечатать только 4-е поле:

perl -MText::CSV_XS -lne 'BEGIN{$csv=Text::CSV_XS->new()} if($csv->parse($_)){ @f=$csv->fields(); print "\"$f[3]\"" }' file

Строка ввода разбита на массив @f
Поле 4 равно $f[3], так как Perl начинает индексацию с 0.

Я предоставил более подробное объяснение Text::CSV_XS в своем ответе здесь: проанализируйте файл csv с помощью gawk

person Chris Koknat    schedule 13.11.2015