【问题标题】:Removing multiple delimiters between outside delimiters on each line删除每行外部分隔符之间的多个分隔符
【发布时间】:2021-02-23 10:48:07
【问题描述】:

在 bash 脚本中使用 awk 或 sed,我需要删除位于内部和外部定界符之间的逗号分隔定界符。问题是错误的值最终出现在错误的列中,其中只需要 3 列。

比如我想转这个:

2020/11/04,Test Account,569.00
2020/11/05,Test,Account,250.00
2020/11/05,More,Test,Accounts,225.00

进入这个:

2020/11/04,Test Account,569.00
2020/11/05,Test Account,250.00
2020/11/05,More Test Accounts,225.00

我尝试使用一些东西,测试正则表达式: 但我找不到只选择逗号以便删除的解决方案。

【问题讨论】:

  • 没有人建议您修复生成错误 CSV 数据的上游进程。
  • 这里有很多使用正则表达式的答案,所以最好保留这个标签来增强这个问题的搜索能力
  • 感谢 anubhav 先生添加标签,OP 已经说明了它的正则表达式问题,不确定为什么要删除标签。

标签: regex string csv awk sed


【解决方案1】:
awk -F, '{ printf "%s,",$1;for (i=2;i<=NF-2;i++) { printf "%s ",$i };printf "%s,%s\n",$(NF-1),$NF }' file

使用 awk,打印第一个以逗号分隔的字段,然后循环遍历该字段的其余部分,直到最后一个但 2 个字段打印该字段后跟一个空格。然后为最后 2 个字段打印最后一个字段,一个逗号,然后是最后一个字段。

【讨论】:

    【解决方案2】:

    使用 GNU awk 将第三个参数匹配():

    $ awk -v OFS=, '{
         match($0,/([^,]*),(.*),([^,]*)/,a)
         gsub(/,/," ",a[2])
         print a[1], a[2], a[3]
    }' file
    2020/11/04,Test Account,569.00
    2020/11/05,Test Account,250.00
    2020/11/05,More Test Accounts,225.00
    

    或使用任何 awk:

    $ awk '
        BEGIN { FS=OFS="," }
        {
            n = split($0,a)
            gsub(/^[^,]*,|,[^,]*$/,"")
            gsub(/,/," ")
            print a[1], $0, a[n]
        }
    ' file
    2020/11/04,Test Account,569.00
    2020/11/05,Test Account,250.00
    2020/11/05,More Test Accounts,225.00
    

    【讨论】:

      【解决方案3】:

      使用这个 Perl 单行代码:

      perl -F',' -lane 'print join ",", $F[0], "@F[1 .. ($#F-1)]", $F[-1];' in.csv
      

      Perl 单行程序使用这些命令行标志:
      -e:告诉 Perl 查找内联代码,而不是在文件中。
      -n:循环输入一行一次,默认将其分配给$_
      -l:在执行内联代码之前剥离输入行分隔符(默认为 *NIX 上的"\n"),并在打印时附加它。-a :在空格或-F 选项中指定的正则表达式上将$_ 拆分为数组@F
      -F',' :在逗号上而不是在空格上拆分为@F

      $F[0]:数组@F的第一个元素(=第一个逗号分隔值)。
      $F[-1]@F的最后一个元素。
      @F[1 .. ($#F-1)]@F的元素在开始的第二个和结束的第二个之间,包括在内。
      "@F[1 .. ($#F-1)]":上述元素,以空格连接成一个字符串。
      join ",", ...:将 LIST "..." 加入一个逗号,并返回结果字符串。

      另请参阅:
      perldoc perlrun: how to execute the Perl interpreter: command line switches

      【讨论】:

        【解决方案4】:
        perl -pe 's{,\K.*(?=,)}{$& =~ y/,/ /r}e' file
        
        sed -e ':a' -e 's/\(,[^,]*\),\([^,]*,\)/\1 \2/; t a' file
        
        awk '{$1=$1","; $NF=","$NF; gsub(/ *, */,","); print}' FS=, file
        
        awk '{for (i=2; i<=NF; ++i) $i=(i>2 && i<NF ? " " : ",") $i} 1' FS=, OFS= file
        

        【讨论】:

          【解决方案5】:

          awk不支持环视,我们可以使用awkmatch函数来实现;使用它,您能否尝试在 GNU awk 中使用所示示例进行跟踪、编写和测试。

          awk '
          match($0,/,.*,/){
            val=substr($0,RSTART+1,RLENGTH-2)
            gsub(/,/," ",val)
            print substr($0,1,RSTART) val substr($0,RSTART+RLENGTH-1)
          }
          ' Input_file
          

          【讨论】:

            【解决方案6】:

            又一个perl

            $ perl -pe 's/(?:^[^,]*,|,[^,]*$)(*SKIP)(*F)|,/ /g' ip.txt
            2020/11/04,Test Account,569.00
            2020/11/05,Test Account,250.00
            2020/11/05,More Test Accounts,225.00
            
            • (?:^[^,]*,|,[^,]*$) 匹配第一个/最后一个字段以及逗号字符
              • (*SKIP)(*F) 这将防止修改前面的正则表达式
            • |, 提供 , 作为备用正则表达式以匹配修改

            使用sed(假设实现支持\n,否则,您必须找到输入中不能出现的字符)

            sed -E 's/,/\n/; s/,([^,]*)$/\n\1/; y/,/ /; y/\n/,/'
            
            • s/,/\n/; s/,([^,]*)$/\n\1/ 用换行符替换第一个和最后一个逗号
            • y/,/ / 用空格替换所有逗号
            • y/\n/,/ 将换行符改回逗号

            【讨论】:

              【解决方案7】:

              在 awk 中与 Timur's 类似的答案

              awk '
                  BEGIN { FS = OFS = "," }
                  function join(start, stop, sep,     str, i) {
                      str = $start
                      for (i = start + 1; i <= stop; i++) {
                          str = str sep $i
                      }
                      return str
                  }
                  { print $1, join(2, NF-1, " "), $NF }
              ' file.csv
              

              可惜 awk 没有内置连接函数

              【讨论】:

                猜你喜欢
                • 2016-08-21
                • 1970-01-01
                • 1970-01-01
                • 2021-07-10
                • 1970-01-01
                • 2022-01-07
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多