sed模式否定用逗号分隔的行

时间:2014-11-08 23:29:37

标签: sed

我有一个文字文件,里面装满了几行:

Female,"$0 to $25,000",Arlington Heights,0,60462,ZD111326,9/18/13 0:21,Disk Drive

我正在尝试将所有逗号,更改为管道|,但引号中的逗号除外。 试图使用sed(我是新手)......它不起作用。使用:

sed '/".*"/!s/\,/|/g' textfile.csv

有什么想法吗?

5 个答案:

答案 0 :(得分:1)

作为测试用例,请考虑以下文件:

Female,"$0 to $25,000",Arlington Heights,0,60462,ZD111326,9/18/13 0:21,Disk Drive
foo,foo,"x,y,z",foo,"a,b,c",foo,"yes,no"
"x,y,z",foo,"a,b,c",foo,"yes,no",foo

这是一个sed命令,用管道符号替换非引用的逗号:

$ sed -r ':a; s/^([^"]*("[^"]*"[^"]*)*),/\1|/g; t a' file 
Female|"$0 to $25,000"|Arlington Heights|0|60462|ZD111326|9/18/13 0:21|Disk Drive
foo|foo|"x,y,z"|foo|"a,b,c"|foo|"yes,no"
"x,y,z"|foo|"a,b,c"|foo|"yes,no"|foo

解释

这会查找出现在双引号的之后的逗号,并用竖线符号替换它们。

  • :a

    这定义了标签a

  • s/^([^"]*("[^"]*"[^"]*)*),/\1|/g

    如果行上的逗号前面有0,2,4或任何偶数引号,则用管道符号替换该逗号。

    • ^

      这在行的开头匹配。

    • (`

      这将启动主要分组(\1)。

    • [^"]*

      这会查找零个或多个非引号字符。

    • ("[^"]*"[^"]*)*

      parens外面的*意味着我们正在寻找parens中的零个或多个模式。 parens中的模式包括引号,任意数量的非引号,引号以及非引号上的任何数字。

      换句话说,此分组仅匹配引号的。由于parens之外的*,它可以匹配任何偶数引号。

    • )

      这将关闭主要分组

    • ,

      这要求分组后跟逗号。

  • t a

    如果上一个s命令成功替换,则test命令会让sed跳回标签a并重试。

    如果没有替换,那么我们就完成了。

答案 1 :(得分:0)

使用awk可能是eaiser:

kent$  cat f
foo,foo,"x,y,z",foo,"a,b,c",foo,"yes,no"
Female,"$0 to $25,000",Arlington Heights,0,60462,ZD111326,9/18/13 0:21,Disk Drive

kent$  awk -F'"' -v OFS='"' '{for(i=1;i<=NF;i++)if(i%2)gsub(",","|",$i)}7' f
foo|foo|"x,y,z"|foo|"a,b,c"|foo|"yes,no"
Female|"$0 to $25,000"|Arlington Heights|0|60462|ZD111326|9/18/13 0:21|Disk Drive

答案 2 :(得分:0)

我建议使用适当的CSV解析器的语言。例如:

ruby -rcsv -ne 'puts CSV.generate_line(CSV.parse_line($_), :col_sep=>"|")' file
Female|$0 to $25,000|Arlington Heights|0|60462|ZD111326|9/18/13 0:21|Disk Drive

答案 3 :(得分:0)

我会使用gnu awks FPAT。它定义了一个字段如何显示FS,告诉分隔符是什么。然后,您可以将输出分隔符设置为|

awk '{$1=$1}1' OFS=\| FPAT="([^,]+)|(\"[^\"]+\")" file
Female|"$0 to $25,000"|Arlington Heights|0|60462|ZD111326|9/18/13 0:21|Disk Drive

如果您的awk不支持FPAT,则可以使用:

awk -F, '{for (i=1;i<NF;i++) {c+=gsub(/\"/,"&",$i);printf "%s"(c%2?FS:"|"),$i}print $NF}' file
Female|"$0 to $25,000"|Arlington Heights|0|60462|ZD111326|9/18/13 0:21|Disk Drive

答案 4 :(得分:0)

sed 's/"\(.*\),\(.*\)"/"\1##HOLD##\2"/g;s/,/|/g;s/##HOLD##/,/g'

这将匹配引号中的文本并为逗号添加占位符,然后将所有其他逗号切换为管道并将占位符放回逗号。您可以将## HOLD ##文本更改为您想要的任何内容。