Разделитель в двойных кавычках, в awk - PullRequest
27 голосов
/ 18 октября 2011

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

Пример

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

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

Ответы [ 3 ]

22 голосов
/ 18 октября 2011

Это просто, с 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

Добавление некоторых комментариев согласно требованию OP.

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

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

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

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

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

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

11 голосов
/ 05 мая 2013

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 для кода и документов

1 голос
/ 14 ноября 2015

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

Предположим, вы хотите напечатать только 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

...