你如何用 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)?的主要内容,如果未能解决你的问题,请参考以下文章