你如何用 awk 解析逗号分隔值(csv)?

Posted

技术标签:

【中文标题】你如何用 awk 解析逗号分隔值(csv)?【英文标题】:how do you parse comma-separated-values (csv) with awk? 【发布时间】:2010-11-29 13:31:48 【问题描述】:

我正在尝试编写一个 awk 脚本来将 CSV 格式的电子表格转换为 XML 以解决 Bugzilla 错误。输入 CSV 的格式如下(从 XLS 电子表格创建并保存为 CSV):

tag_1,tag_2,...,tag_N
value1_1,value1_2,...,value1_N
value2_1,value2_2,...,value2_N
valueM_1,valueM_2,...,valueM_N

标题列表示 XML 标记的名称。上述转换为 XML 的文件应如下所示:

<element>
    <tag_1>value1_1</tag_1>
    <tag_2>value1_2</tag_2>
    ...
    <tag_N>value1_N</tag_N>
</element>
<element>
    <tag_1>value2_1</tag_1>
    <tag_2>value2_2</tag_2>
    ...
    <tag_N>value2_N</tag_N>
</element>
...

我必须完成的 awk 脚本如下:

BEGIN OFS = "\n"
NR == 1 for (i = 1; i <=NF; i++)
            tag[i]=$i
         print "<bugzilla version=\"3.4.1\" urlbase=\"http://mozilla.com/\" maintainer=\"somebody@mozilla.com\" exporter=\"somebody.else@mozilla.com\">"
NR != 1 print "   <bug>"
         for (i = 1; i <= NF; i++)
            print "      <" tag[i] ">" $i "</" tag[i] ">"
         print "   </bug>"
END print "</bugzilla>"

实际的 CSV 文件是:

cf_foo,cf_bar,short_desc,cf_zebra,cf_pizza,cf_dumpling ,assigned_to,bug_status,cf_word,cf_caslte
ABCD,A-BAR-0032,A NICE DESCRIPTION - help me,pretty,Pepperoni,,,NEW,,

实际输出为:

$ awk -f csvtobugs.awk bugs.csv

<bugzilla version="3.4.1" urlbase="http://mozilla.com/" maintainer="somebody@mozilla.com" exporter="somebody.else@mozilla.com">
   <bug>
      <cf_foo,cf_bar,short_desc,cf_zebra,cf_pizza,cf_dumpling>ABCD,A-BAR-0032,A</cf_foo,cf_bar,short_desc,cf_zebra,cf_pizza,cf_dumpling>
      <,assigned_to,bug_status,cf_word,cf_caslte>NICE</,assigned_to,bug_status,cf_word,cf_caslte>
      <>DESCRIPTION</>
      <>-</>
      <>help</>
      <>me,pretty,Pepperoni,,,NEW,,</>
   </bug>
   <bug>
   </bug>
</bugzilla>

显然,这不是预期的结果(我承认,我从这个论坛复制粘贴了这个脚本:http://www.unix.com/shell-programming-scripting/21404-csv-xml.html)。问题是我已经很久没有看过 awk 脚本了,我不知道语法是什么意思。

【问题讨论】:

【参考方案1】:

您需要在BEGIN 规则中设置FS = "," 以使用逗号作为字段分隔符;如果字段分隔符是制表符,则显示的代码应该可以工作,这是一种不同的(也是流行的)约定,即使不使用逗号,文件也通常仍称为“CSV”;-)。

【讨论】:

你也可以使用-F,作为awk的选项【参考方案2】:

使用你知道的工具:)

那个 awk 脚本看起来并不处理 " 和其他 CSV 奇怪的东西。(我认为它只是在选项卡上拆分 - 因为其他答案指出它需要更改为拆分,)python、perl .Net 等有对象要完全处理 CSV 和 XML,您可能可以用 awk 脚本中的几个字符编写解决方案,更重要的是要理解它。

【讨论】:

嘿,没多久吧?我自己想出了答案,但只能在第一个答案后 2 秒发布(我的答案可以说更好,因为我包含更多信息):)【参考方案3】:

请记住,在 csv 中用逗号分割是可以的,直到您遇到以下情况:

1997,Ford,E350,"Super, luxurious truck"

在这种情况下,它会将“超级豪华卡车”拆分为两个不正确的项目。我建议使用另一种语言的 csv 库作为上述帖子中的“标记”状态。

【讨论】:

我通过切换到“TSV”导出(制表符分隔值)解决了这个问题。主文件是 Excel 工作表,我不需要一直这样做。我正在将团队从基于 Excel 的跟踪器(用于“敏捷”方法中的“故事”)迁移到 Bugzilla。现在,每个故事都作为 Bugzilla 中的错误保存。我们正在使用 Eclipse Mylyn 插件将故事作为任务拉入 IDE。比 Excel 解决方案 IMO 好得多。无论如何,这个初始导入只需要发生一次——我不想为此学习 Perl。 AWK 脚本运行良好 :)【参考方案4】:

我可以通过更改 FS(字段分隔符)来修复它:

BEGIN 
    FS=",";
    OFS = "\n"
NR == 1 for (i = 1; i <=NF; i++)
            tag[i]=$i
         print "<bugzilla version=\"3.4.1\" urlbase=\"http://mozilla.com/\" maintainer=\"somebody@mozilla.com\" exporter=\"somebody.else@mozilla.com\">"
NR != 1 print "   <bug>"
         for (i = 1; i <= NF; i++)
            print "      <" tag[i] ">" $i "</" tag[i] ">"
         print "   </bug>"
END print "</bugzilla>"

输出:

<bugzilla version="3.4.1" urlbase="http://mozilla.com/" maintainer="somebody@mozilla.com" exporter="somebody.else@mozilla.com">
   <bug>
      <cf_foo>ABCD</cf_foo>
      <cf_bar>A-BAR-0032</cf_bar>
      <short_desc>A NICE DESCRIPTION - help me</short_desc>
      <cf_zebra>pretty</cf_zebra>
      <cf_pizza>Pepperoni</cf_pizza>
      <cf_dumpling ></cf_dumpling >
      <assigned_to></assigned_to>
      <bug_status>NEW</bug_status>
      <cf_word></cf_word>
      <cf_caslte></cf_caslte>
   </bug>
</bugzilla>

【讨论】:

【参考方案5】:

您可以使用各种技巧,例如设置 FS。更多技巧可以在 Awk 新闻组中找到。还有像我这样的解析器:http://lorance.freeshell.org/csv/

【讨论】:

【参考方案6】:

你可以试试我的csvprintf。它可以将 CSV 转换为 XML,然后您可以根据需要使用 XSLT 设置样式。

【讨论】:

以上是关于你如何用 awk 解析逗号分隔值(csv)?的主要内容,如果未能解决你的问题,请参考以下文章

字符串 CSV解析 表格 逗号分隔值

如何在 BASH 中将制表符分隔值 (TSV) 文件转换为逗号分隔值 (CSV) 文件?

将 hive 查询输出拆分为逗号分隔值

excel另存为csv打开后有大量逗号是怎么回事?

在变量 BASH 的一行中用逗号分隔值

如何在 Bash 脚本中解析 CSV?