【问题标题】:Confining Substitution to Match Space Using sed?使用 sed 限制替换以匹配空间?
【发布时间】:2011-03-07 10:08:17
【问题描述】:

有没有办法使用 sed 仅在匹配空间内进行替换?

即鉴于以下行,有没有办法只替换“。”包含在匹配单引号中并保护“。”的字符没有用单引号括起来的字符?

输入:

'ECJ-4YF1H10.6Z' ! 'CAP' ! '10.0uF' ! 'TOL' ; MGCDC1008.S1 MGCDC1009.A2

想要的结果:

'ECJ-4YF1H10-6Z' ! 'CAP' ! '10_0uF' ! 'TOL' ; MGCDC1008.S1 MGCDC1009.A2

或者这只是 perl 或 awk 可能更适合的工作?

感谢您的帮助,

标记

【问题讨论】:

    标签: sed


    【解决方案1】:

    尝试以下使用分治法的方法:

    sed "s/\('[^']*'\)/\n&\n/g;s/\(\n'[^.]*\)\.\([^']*Z'\)/\1-\2/g;s/\(\n'[^.]*\)\.\([^']*uF'\)/\1_\2/g;s/\n//g" inputfile
    

    解释:

    • s/\('[^']*'\)/\n&\n/g - 在每对单引号前后添加换行符及其内容
    • s/\(\n'[^.]*\)\.\([^']*Z'\)/\1-\2/g - 使用换行符和单引号作为键,用破折号替换以“Z”结尾的字符串的点
    • s/\(\n'[^.]*\)\.\([^']*uF'\)/\1_\2/g - 使用换行符和单引号作为键,用破折号替换以“uF”结尾的字符串
    • s/\n//g - 删除第一步添加的换行符

    您可以将命令限制为仅作用于某些行:

    sed "/foo/{s/\('[^']*'\)/\n&\n/g;s/\(\n'[^.]*\)\.\([^']*Z'\)/\1-\2/g;s/\(\n'[^.]*\)\.\([^']*uF'\)/\1_\2/g;s/\n//g}" inputfile
    

    你可以用一些正则表达式代替“foo”。

    sed 的某些版本喜欢用勺子喂(而不是命令之间的分号,使用-e):

    sed -e "/foo/{s/\('[^']*'\)/\n&\n/g" -e "s/\(\n'[^.]*\)\.\([^']*Z'\)/\1-\2/g" -e "s/\(\n'[^.]*\)\.\([^']*uF'\)/\1_\2/g" -e "s/\n//g}" inputfile
    

    【讨论】:

    • 非常感谢,丹尼斯!我完全忽略了临时修改行结构以在多行模式上操作的可能性。
    【解决方案2】:
    $ cat phoo1234567_sedFix.sed
    #! /bin/sed -f
    /'[0-9][0-9]\.[0-9][a-zA-Z][a-zA-Z]'/s/'\([0-9][0-9]\)\.\([0-9][a-zA-Z][a-zA-Z]\)'/\1_\2/
    

    这回答了您的具体问题。如果您需要修复的模式并不总是像您提供的示例那样,那么您将需要此行的多个副本,并修改 reg 表达式以匹配您的新更改目标。

    请注意,cmd 分为两部分,“/'[0-9][0-9].[0-9][a-zA-Z][a-zA-Z]'/”表示,必须与此模式匹配行,而尾随 "s/'([0-9][0-9]).([0-9][a-zA-Z][a-zA-Z])'/ \1_\2/",是进行替换的部分。您可以在最后的 '/' 之后添加一个 'g' 以使这种替换发生在每行中此模式的所有实例上。

    匹配模式中的 \(\) 对被转换为命令替换端的编号缓冲区(即 \1 \2)。这就是 awk 所没有的 sed 功能。

    如果您要做很​​多此类工作,我强烈推荐 O'Rielly 的 Sed And Awk 书。通过 sed 的工作原理所花费的时间将得到多次回报。

    我希望这会有所帮助。

    附:由于您似乎是新用户,如果您得到的答案对您有帮助,请记住将其标记为已接受,或者给它一个 +(或 -)作为有用的答案。

    【讨论】:

    • 感谢您的回复,庇护所。一段时间以来,我一直在努力设计一个能够最大限度地减少比赛贪婪的正则表达式,然后 dennis-williamson 提示我首先拆分线路。之后就小菜一碟了;^)
    【解决方案3】:

    这是最适合 awk 或任何支持破坏/拆分字符串的语言的工作。 IMO 使用 sed 完成这项任务,它是基于正则表达式的,虽然可行,但难以阅读和调试,因此不是最适合这项工作的工具。无意冒犯 sed 狂热分子。

    awk '{
      for(i=1;i<=NF;i++)  {
         if ($i ~ /\047/ ){
            gsub(".","_",$i)
         }
      } 
    }1' file
    

    上面说对于每个字段(字段分隔符默认为空格),检查是否有单引号,如果有,替换“。”至 ”_”。这种方法很简单,不需要复杂的正则表达式。

    【讨论】:

    • 感谢您的回复,kruimi,我同意您的分析,即 awk 或 perl 是进行此类操作的更好工具。 @dennis-williamson 睁开眼睛欺骗 sed 在替换之前将阵容拆分,然后再将其重新组合。
    • @phoo1234567,我相信现在看 sed 解决方案你的眼睛已经累了 :)
    猜你喜欢
    • 1970-01-01
    • 2022-01-18
    • 2013-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-09
    • 2017-03-20
    • 1970-01-01
    相关资源
    最近更新 更多