在 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.
需要一些解决方案来在 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.