【问题标题】:How to Convert a tab delimited file with commas in values to .CSV and the values with commas to be enclosed in double quotes?如何将带有逗号的制表符分隔文件转换为 .CSV 并将带有逗号的值括在双引号中?
【发布时间】:2013-10-02 16:01:29
【问题描述】:

我有一个从特定供应商的门户网站下载的 .CSV 文件(比如说 tab_delimited_file.csv)。当我将文件移动到我的一个 Linux 目录时,我注意到这个特定的 .CSV 文件实际上是一个 制表符分隔 文件,它被命名为 .CSV。请在下面找到该文件的几个示例记录。

"""column1"""   """column2"""   """column3"""   """column4"""   """column5"""   """column6"""   """column7"""  
12  455 string with quotes, and with a comma in between 4432    6787    890 88  
4432    6787    another, string with quotes, and with two comma in between  890 88  12  455  
11  22  simple string   77  777 333 22

以上示例记录以tabs 分隔。我知道文件的标题很奇怪,但这是我收到文件格式的方式。

我尝试使用 tr 命令将tabs 替换为commas,但由于记录值中多余的逗号,文件完全被弄乱了。我需要将带有逗号的记录值括在双引号中。我使用的命令如下。

tr '\t' ',' < tab_delimited_file.csv > comma_separated_file.csv    

这会将文件转换为以下格式。

"""column1""","""column2""","""column3""","""column4""","""column5""","""column6""","""column7"""
12,455,string with quotes, and with a comma in between,4432,6787,890,88
4432,6787,another, string with quotes, and with two comma in between,890,88,12,455
11,22,simple string,77,777,333,22

我需要帮助将示例文件转换为以下格式。

column1,column2,column3,column4,column5,column6,column7
12,455,"string with quotes, and with a comma in between",4432,6787,890,88
4432,6787,"another, string with quotes, and with two comma in between",890,88,12,455
11,22,"simple string",77,777,333,22

使用 sedawk 的任何解决方案都会非常有用。

【问题讨论】:

    标签: linux sed awk csv


    【解决方案1】:

    这将产生您要求的输出,但尚不清楚我假设的条件是否正确,例如,哪些字段放在引号中(任何包含逗号或空格的字段)实际上是您的想用其他输入自己测试一下:

    $ awk 'BEGIN { FS=OFS="\t" }
      {
         gsub(/"/,"")
         for (i=1;i<=NF;i++)
             if ($i ~ /[,[:space:]]/)
                 $i = "\"" $i "\""
         gsub(OFS,",")
         print
      }
      ' file
    column1,column2,column3,column4,column5,column6,column7
    12,455,"string with quotes, and with a comma in between",4432,6787,890,88
    4432,6787,"another, string with quotes, and with two comma in between",890,88,12,455
    11,22,"simple string",77,777,333,22
    

    【讨论】:

    • 我知道你为我的这个问题提供解决方案已经很久了,很抱歉现在再次打扰你......我必须再次使用这段代码,所以如果可能的话,你能请解释一下以帮助我理解上述代码的作用?这将非常有帮助...谢谢...
    • 我用了你的答案,我也+1d了...我一开始不知道如何使用SO,所以没有接受答案...:(
    【解决方案2】:

    一种使用的方式:

    awk '
        BEGIN { FS = "\t"; OFS = "," }
        FNR == 1 {
            for ( i = 1; i <= NF; i++ ) { gsub( /"+/, "", $i ) }
            print $0
            next
        }
        FNR > 1 {   
            for ( i = 1; i <= NF; i++ ) {
                w = split( $i, _, " " )
                if ( w > 1 ) { $i = "\"" $i "\"" }
            }
            print $0
        }
    ' infile
    

    它使用制表符来分割输入中的字段,并使用逗号来写入输出。对于标题很简单,只需删除所有双引号即可。对于数据行,只有当拆分返回多个字段时,每个字段用空格分隔并用双引号括起来。

    它产生:

    column1,column2,column3,column4,column5,column6,column7  
    12,455,"string with quotes, and with a comma in between",4432,6787,890,88  
    4432,6787,"another, string with quotes, and with two comma in between",890,88,12,455  
    11,22,"simple string",77,777,333,22
    

    【讨论】:

    • 您不需要测试FNR &gt; 1,因为您必须满足该条件才能到达该行。您可以使用if ($i ~ / /) 而不是w = split( $i, _, " " ); if ( w &gt; 1 ) 来测试字符串是否包含空白字符。你可以直接说print 而不是print $0
    • @EdMorton:谢谢。你说的对。这些更改很好,但会改变我的解决方案,所以我会保持原样。
    猜你喜欢
    • 1970-01-01
    • 2020-11-24
    • 2018-04-03
    • 2015-06-10
    • 1970-01-01
    • 1970-01-01
    • 2021-07-21
    • 2018-04-02
    • 1970-01-01
    相关资源
    最近更新 更多