在 bash 中用逗号替换管道,CSV 中的大括号之间除外

Replace pipe with comma except between curly braces in CSV in bash

需要一些解决方案来在 CSV 文件的特定列中用逗号替换管道,它也有一些键值作为管道分隔的字符串(可以是任何数字,一个或多个)。

基本上需要替换不在花括号内的管道,即 {subStringX441|subStringX442|subStringX443|subStringX444} 应该保持不变。

不能使用简单的 sed -i -e 's\|\,\g' filename,因为它将替换所有管道。

输入:

column1,column2,column3,column4,column5,column6,column7

stringX1,stringX2,stringX3,stringX41|stringX42|stringX43|stringX44={subStringX441|subStringX442|subStringX443|subStringX444}|stringX45,stringX5,stringX6,stringX7

stringY1,stringY2,stringY3,stringY41|stringY42|stringY43|stringY44={subStringY441|subStringY442|subStringY443}|stringY45,stringY5,stringY6,stringY7

期望输出:

column1,column2,column3,column4a,column4b,column4c,column4d,column4e,column5,column6,column7

stringX1,stringX2,stringX3,stringX41,stringX42,stringX43,stringX44={subStringX441|subStringX442|subStringX443|subStringX444},stringX45,stringX5,stringX6,stringX7

stringY1,stringY2,stringY3,stringY41,stringY42,stringY43,stringY44={subStringY441|subStringY442|subStringY443},stringY45,stringY5,stringY6,stringY7

正则表达式(严格意义上)不足以处理平衡括号(最后暗示至少 Chomsky Type-2)。我将按照以下方式使用 GNU AWK 完成此任务,让 file.txt 内容为

stringY1,stringY2,stringY3,stringY41|stringY42|stringY43|stringY44
{subStringY441|subStringY442|subStringY443}|stringY45,stringY5,stringY6,stringY7

然后

awk 'BEGIN{FPAT=".";OFS=""}{for(i=1;i<=NF;i+=1){if($i=="{"){inside=1};if($i=="}"){inside=0};if(!inside && $i=="|"){$i=","}};print}' file.txt

输出

stringY1,stringY2,stringY3,stringY41,stringY42,stringY43,stringY44
{subStringY441|subStringY442|subStringY443},stringY45,stringY5,stringY6,stringY7

说明:我通知 GNU AWK 使用 FPAT 变量将任何单个字符视为字段,使用 OFS 变量输出字段分隔符为空字符串。对于每一行,我使用 for 循环遍历后续字段(即字符),如果字符为 {,则我将变量 inside 设置为 1,如果字符为 [=22] =] 然后我将变量设置为 0,然后如果我们不是 (!) 并且 (&&) 字符是 |,则将其更改为 ,。处理完第 I 行的所有字符后 print.

免责声明 此解决方案假定大括号从不嵌套,并且每个 { 在给定行中都有匹配的 }

(在 gawk 4.2.1 中测试)

使用sed

$ sed 's/\({[^}]*\)\||/,/g;s/,{/{/;1s/column4/&a,&b,&c,&d,&e/' input_file
column1,column2,column3,column4a,column4b,column4c,column4d,column4e,column5,column6,column7

stringX1,stringX2,stringX3,stringX41,stringX42,stringX43,stringX44={subStringX441|subStringX442|subStringX443|subStringX444},stringX45,stringX5,stringX6,stringX7

stringY1,stringY2,stringY3,stringY41,stringY42,stringY43,stringY44={subStringY441|subStringY442|subStringY443},stringY45,stringY5,stringY6,stringY7

这可能适合您 (GNU sed):

sed  ':a;s/\({[^|}]*\)|\([^}]*}\)/\n/g;ta;y/\n|/|,/' file

用换行符替换 {...} 之间的 |,然后将换行符转换为 |,将 | 转换为 ,' s.