【问题标题】:Replace pipe with comma except between curly braces in CSV in bash用逗号替换管道,除了bash中CSV中的花括号之间
【发布时间】:2022-01-21 21:14:51
【问题描述】:

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

【问题讨论】:

  • 欢迎使用 StackOverflow。我可以建议你看看help center,尤其是How do I format my posts using Markdown or HTML?吗?
  • 通常的解决方案是使用 CSV 解析器,但您的示例数据看起来并不像有效的 CSV。因此,您必须首先定义如何识别数据中的 。也许 awk 解决方案会更合适,但如果不了解更多关于您的数据的信息,很难推荐可靠的解决方案。

标签: bash shell awk sed


【解决方案1】:

正则表达式(严格意义上的)不足以处理平衡括号(最后暗示至少 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,如果字符为},则将变量设置为0 , 那么如果我们不在 (!) 内部并且 (&amp;&amp;) 字符是 | 将其更改为 ,。处理完第一行中的所有字符print

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

(在 gawk 4.2.1 中测试)

【讨论】:

    【解决方案2】:

    使用sed

    $ sed 's/\({[^}]*\)\||/,\1/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
    

    【讨论】:

      【解决方案3】:

      这可能对你有用(GNU sed):

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

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

      【讨论】:

        猜你喜欢
        • 2016-04-19
        • 2015-10-05
        • 1970-01-01
        • 2022-12-30
        • 2017-12-02
        • 2016-11-13
        • 2017-11-17
        • 2019-10-08
        • 2018-05-14
        相关资源
        最近更新 更多