34

我正在使用 awk 以“,”作为分隔符解析我的数据,因为输入是一个 csv 文件。但是,数据中有“,”,由双引号(“...”)转义。

例子

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

如何忽略双引号中的逗号“,”以便可以使用 awk 正确解析输出?我知道我们可以在 excel 中做到这一点,但我们如何在 awk 中做到这一点?

4

3 回答 3

28

使用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 的正则表达式要求每个字段至少包含一个字符。直接修改(将第一个 '<code>+' 更改为 '<code>*')允许字段为空:

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

于 2011-10-18T16:12:11.440 回答
12

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

于 2013-05-04T23:49:33.813 回答
0

Perl 等成熟的 CSV 解析器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我在这里的答案 中提供了更多解释: parse csv file using gawk

于 2015-11-13T22:19:23.273 回答