【问题标题】:Replace first two whitespace occurrences with a comma using sed使用 sed 将前两个空格替换为逗号
【发布时间】:2011-09-30 21:56:43
【问题描述】:

我有一个以空格分隔的文件,每行的条目数不定。我想用逗号替换前两个空格,以创建一个逗号分隔的三列文件。

这是我的意见:

a b  1 2 3 3 2 1
c d  44 55 66 2355
line http://google.com 100 200 300
ef jh  77 88 99
z y 2 3 33

这是我想要的输出:

a,b,1 2 3 3 2 1
c,d,44 55 66 2355
line,http://google.com,100 200 300
ef,jh,77 88 99
z,y,2 3 33

我正在尝试在 sed 命令中使用 perl 正则表达式,但我无法让它正常工作。首先我尝试捕获一个单词,然后是一个空格,然后是另一个单词,但这仅适用于第 1、2 和 5 行:

$ cat test | sed -r 's/(\w)\s+(\w)\s+/\1,\2,/'
a,b,1 2 3 3 2 1
c,d,44 55 66 2355
line http://google.com 100 200 300
ef jh  77 88 99
z,y,2 3 33

我也尝试捕获空格、一个单词,然后是更多的空格,但这给了我相同的结果:

$ cat test | sed -r 's/\s+(\w)\s+/,\1,/'
a,b,1 2 3 3 2 1
c,d,44 55 66 2355
line http://google.com 100 200 300
ef jh  77 88 99
z,y,2 3 33

我也尝试使用 .?通配符,但这对第 4 行有一些有趣的影响。

$ cat test | sed -r 's/\s+(.?)\s+/,\1,/'
a,b,1 2 3 3 2 1
c,d,44 55 66 2355
line http://google.com 100 200 300
ef jh,,77 88 99
z,y,2 3 33

非常感谢任何帮助!

【问题讨论】:

    标签: regex perl parsing command-line sed


    【解决方案1】:

    这个怎么样:

    sed -e 's/\s\+/,/' | sed -e 's/\s\+/,/'
    

    使用单个 sed 命令可能是可能的,但这肯定是一种简单的方法 :)

    我的输出:

    a,b,1 2 3 3 2 1
    c,d,44 55 66 2355
    line,http://google.com,100 200 300
    ef,jh,77 88 99
    z,y,2 3 33
    

    【讨论】:

    • 谢谢,工作就像一个魅力。我肯定让这太复杂了!
    【解决方案2】:

    试试这个:

    sed -r 's/\s+(\S+)\s+/,\1,/'
    

    刚刚在您的一次尝试中将\w(一个“单词”字符)替换为\S+(一个或多个非空格字符)。

    【讨论】:

      【解决方案3】:

      您可以通过提供多个-e 参数来为sed 的单个实例提供多个命令。

      要做前两个,只需使用:

      sed -e 's/\s\+/,/' -e 's/\s\+/,/'
      

      这基本上是按顺序在行上运行两个命令,第一个执行第一个空白块,第二个执行下一个。

      以下记录显示了这一点:

      pax$ echo 'a b  1 2 3 3 2 1
      c d  44 55 66 2355
      line http://google.com 100 200 300
      ef jh  77 88 99
      z y 2 3 33
      ' | sed -e 's/\s\+/,/' -e 's/\s\+/,/'
      
      a,b,1 2 3 3 2 1
      c,d,44 55 66 2355
      line,http://google.com,100 200 300
      ef,jh,77 88 99
      z,y,2 3 33
      

      【讨论】:

        【解决方案4】:

        Sed s/// 支持一种方式来说明要替换哪个模式的出现:只需将n 添加到命令末尾即可仅替换第nth 出现。因此,要替换第一次和第二次出现的空白,只需这样使用:

        $ sed 's/  */,/1;s/  */,/2' input
        a,b ,1 2 3 3 2 1
        c,d ,44 55 66 2355
        line,http://google.com 100,200 300
        ef,jh ,77 88 99
        z,y 2,3 33
        

        编辑:阅读另一个提议的解决方案时,我注意到s/ */,/ 之后的12 不仅没有必要,而且显然是错误的。默认情况下,s/// 只是替换模式的第一次出现。因此,如果我们有两个相同的s///,它们将替换第一个和第二个出现。你需要的只是

        $ sed 's/  */,/;s/  */,/' input 
        

        (请注意,如果用分号分隔两个 sed 命令,则可以将它们放在一个表达式中。某些 sed 实现不接受 s/// 命令后的分号;在这种情况下,使用换行符分隔命令。 )

        【讨论】:

          【解决方案5】:

          Perl 解决方案是:

          perl -pe '$_=join ",", split /\s+/, $_, 3' some.file
          

          【讨论】:

          • 另一个 Perl 解决方案不会有什么坏处,因为这个问题是用 Perl 和 Sed 标签标记的。 perl -pe 's/([^\s,]+)\s/$1.(my$c++<3&& ",")." "/eg' 实际上,我更喜欢同一个线程中显示的 join/split 方法,但稍加工作就有一个 s///eg 替代方案。此方法跟踪已执行的替换次数,并且仅在每行的前 3 次用逗号替换。也许有一天会有 /g{3} 选项将 m//g 或 s///g 限制为三个匹配项。
          • 如果使用 Perl,至少使用自动拆分。 ;-)
          • 例如:perl -anE 'say "$F[0],$F[1],$F[2] $F[3..$#F]"'
          • 我想应该是perl -anE 'say "$F[0],$F[1],$F[2] @F[3..$#F]"'
          【解决方案6】:

          不确定 sed/perl,但这是一个(丑陋的)awk 解决方案。它只打印字段 1-2,以逗号分隔,然后打印其余字段以空格分隔:

          awk '{
            printf("%s,", $1)
            printf("%s,", $2)
            for (i=3; i<=NF; i++)
              printf("%s ", $i)
              printf("\n")
          }' myfile.txt
          

          【讨论】:

            猜你喜欢
            • 2013-12-10
            • 1970-01-01
            • 2017-05-29
            • 2015-01-13
            • 2014-11-27
            • 2014-08-03
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多