【问题标题】:sed replace between two strings wildcardsed 在两个字符串之间替换通配符
【发布时间】:2015-01-12 01:10:33
【问题描述】:

我正在尝试标记颜色标签内的所有内容并将其替换为其他内容,例如:

I have a [color=blue]dog[/color] and a [color=blue]cat[/color] in my house.

到

I have a [color=blue][b]foobar[/b][/color] and a [color=blue][b]foobar[/b][/color] in my house.

这是我尝试过的:

sample='I have a [color=blue]dog[/color] and a [color=blue]cat[/color] in my house.'
replace='foobar'
sample=$(echo $sample| sed "s/\[color=blue\].*\[\/color\]/\[color=blue\]\[b\]$replace\[\/b\]\[\/color\]/g")

这让我很兴奋:

I have a [color=blue][b]foobar[/b][/color] in my house.

关于在这种情况下如何使 sed 不贪婪的任何想法?

【问题讨论】:

    标签: regex bash sed wildcard non-greedy


    【解决方案1】:

    只需将您的.* 替换为[^[]*(左括号以外的任何字符)。那就是:

    "s/\[color=blue\][^[]*\[\/color\]/\[color=blue\]\[b\]$replace\[\/b\]\[\/color\]/g"
    

    【讨论】:

      【解决方案2】:

      sed 总是贪婪的。您可以通过仔细选择正则表达式来解决它。下面的示例与您的示例相同,只是 .* 已替换为 [^[]*(这意味着 除了 [ 之外的所有内容):

      $ echo $sample| sed "s/\[color=blue\][^[]*\[\/color\]/\[color=blue\]\[b\]$replace\[\/b\]\[\/color\]/g"
      I have a [color=blue][b]foobar[/b][/color] and a [color=blue][b]foobar[/b][/color] in my house.
      

      对于真正非贪婪的正则表达式,请尝试 perl 或 python。

      【讨论】:

        【解决方案3】:
          sed 's#\(\[color=[[:alpha:]]*\]\)[[:alnum:]]*\(\[/color\)#\1[b]foobar[/b]\2#g'
        

        例子

        echo 'I have a [color=blue]dog[/color] and a [color=blue]cat[/color] in my house.'|sed 's#\(\[color=[[:alpha:]]*\]\)[[:alnum:]]*\(\[/color\)#\1[b]\2#g'
        

        输出

          I have a [color=blue][b]foobar[/b][/color] and a [color=blue][b]foobar[/b][/color] in my house.
        

        【讨论】:

          【解决方案4】:
          sed -r 's/(\[color=[a-z]*\])[a-z]*(\[\/color\])/\1[b]foobar[\/b]\2/g' File
          

          或

          sed 's/\(\[color=[a-z]*\]\)[a-z]*\(\[\/color\]\)/\1[b]foobar[\/b]\2/g' File
          

          解释: 在这里,我们使用( 和) 查找1. [color=any small letter sequence] 后跟2. any small letter sequence 后跟3. [/color] 和组模式1 and 3 的模式。然后我们进行替换。我们保留1st and 2nd groups(使用\1和\2),但将第一组和第二组之间的内容替换为[b]foobar[/b]。

          【讨论】:

          • 此答案因其长度和内容而被标记为低质量。你能解释一下你的代码吗?
          • @A.M.D 你不必在替换中反斜杠。
          【解决方案5】:

          sed 永远是贪婪的。如果您严格想要非贪婪变体,您可以使用perl:

          $ echo $test
          I have a [color=blue]dog[/color] and a [color=blue]cat[/color] in my house.
          
          $ perl -pne 's/(\[color=[a-zA-Z]*\])(.*?)(\[\/color\])/$1\[b\]foobar\[\/b\]$3/g' <<< "$test"
          I have a [color=blue][b]foobar[/b][/color] and a [color=blue][b]foobar[/b][/color] in my house.
          

          我想,您可以在这里解释大部分正则表达式,除了微小的语法变化:
          (.*?) 代替 (.*) 指示匹配应该是非贪婪的。
          如果你在.* 之后跳过?,这是你当前必须得到的输出:

          $ perl -pne 's/(\[color=[a-zA-Z]*\])(.*)(\[\/color\])/$1\[b\]foobar\[\/b\]$3/g' <<< "$test"
          I have a [color=blue][b]foobar[/b][/color] in my house.
          

          【讨论】:

            【解决方案6】:

            正如其他人所说,您需要通过阅读不匹配的字符来使用非贪婪。

            在方括号[^ABC] 中使用克拉实际上并不意味着后面的任何内容。

            因此,将其与 asterix * 一起使用将只匹配该字符的下一个。


            例如

            [^[]*
            

            将匹配所有内容直到下一个[ 括号

            而且每个人都用反斜杠转义了不需要的替换,因为它不能打印正则表达式。

            无论如何这里是一个应该工作的命令。

            sed 's/\(\[color[^]]*\]\)[^[]*\(\[\/color\]\)/\1[b]foobar\[b]\2/g'
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2021-07-23
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-04-22
              • 1970-01-01
              • 2022-10-24
              相关资源
              最近更新 更多