将双引号外的每个逗号替换为管道

Que*_*tin 6 sed regular-expression csv

使用 sed,我想用双引号之外的每个逗号替换管道。

这样 .csv 文件中的这一行:

John,Tonny,"345.3435,23",56th Street
Run Code Online (Sandbox Code Playgroud)

将转换为:

John|Tonny|"345.3435,23"|56th Street
Run Code Online (Sandbox Code Playgroud)

你能帮我处理正则表达式吗?

Kus*_*nda 14

使用csvkit

$ csvformat -D '|' file.csv
John|Tonny|345.3435,23|56th Street
Run Code Online (Sandbox Code Playgroud)

csvkit 中的工具知道如何处理 CVS 文件的复杂性,在这里我们使用正确csvformat替换分隔逗号|。将根据需要引用输出字段。

例子:

$ cat file.csv
John,Tonny,"345.3435,23",56th Street
The | factory,Ltd.,"0,0",meep meep

$ csvformat -D '|' file.csv
John|Tonny|345.3435,23|56th Street
"The | factory"|Ltd.|0,0|meep meep
Run Code Online (Sandbox Code Playgroud)


Sté*_*las 10

如果您sed支持该-E选项(-r在某些实现中):

sed -Ee :1 -e 's/^(([^",]|"[^"]*")*),/\1|/;t1' < file
Run Code Online (Sandbox Code Playgroud)

:label
   s/pattern/replacement/
t label
Run Code Online (Sandbox Code Playgroud)

是一个很常见的sed成语。只要成功,它就会在循环中不断进行相同的替换。

在这里,我们替换由 0 个或多个带引号的字符串或字符组成的行的前导部分,"并且,(在 中捕获\1)后跟,带有该\1捕获的 a 和 a |,因此在您的示例中,这意味着:

  • John,Tonny,"345.3435,23",56th Street -> John|Tonny,"345.3435,23",56th Street
  • John|Tonny,"345.3435,23",56th Street -> John|Tonny|"345.3435,23",56th Street
  • John|Tonny|"345.3435,23",56th Street -> John|Tonny|"345.3435,23"|56th Street
  • 我们停在这里,因为模式不再匹配了。

使用perl,您可以使用以下g标志替换:

perl -pe 's{("[^"]*"|[^",]+)|,}{$1 // "|"}ge'
Run Code Online (Sandbox Code Playgroud)

在这里,假设引号在输入中是平衡的,模式将匹配所有输入,将其分解为:

  • 带引号的字符串
  • ,or以外的字符序列"
  • 逗号

并且仅当匹配的字符串是逗号时($1在替换部分中未定义时),将其替换为|.

  • @Sundeep,你的不会处理像`,foo` 或`",foo"` 或`"x",",y"` 这样的输入 (2认同)
  • @Sundeep,或`"a,b"` 或`a,"b,c"` 或`a,,b` (2认同)