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

时间:2009-09-18 16:52:06

标签: xml unix shell csv awk

我正在尝试编写一个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脚本以来,它已经很久了,而且我没有IDEA语法意味着什么。

6 个答案:

答案 0 :(得分:4)

您需要在FS = ","规则中设置BEGIN以使用逗号作为字段分隔符;如果字段分隔符是一个选项卡,则显示它的代码应该有效,这是一个不同的(也是流行的)常规文件,通常仍被称为“CSV”,即使不使用逗号; - )。

答案 1 :(得分:1)

使用您知道的工具:)

awk脚本看起来不会处理“和其他CSV奇怪。(我认为它只是在选项卡上分裂 - 因为其他答案注意它需要更改为拆分,)python,perl .Net等有对象要完全处理CSV和XML,可能你可以用awk脚本中的字符编写解决方案,更重要的是要理解它。

答案 2 :(得分:1)

请记住,在获得以下方案之前,在csv中使用逗号分割是正常的:

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

在这种情况下,它会将“超级豪华卡车”分成两个不正确的项目。我建议在另一种语言中使用csv libs,如上面帖子中的“Mark”所述。

答案 3 :(得分:0)

我能够通过更改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>

答案 4 :(得分:0)

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

答案 5 :(得分:0)

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