【问题标题】:Sed regex and substring negationSed 正则表达式和子字符串否定
【发布时间】:2012-02-21 14:40:18
【问题描述】:

查找与特定模式匹配的子字符串(前后为特定字符串的字符串)的正确语法是什么?

例如,我想获取所有 BEGIN_ 开始_END 结束 并且中间的子字符串 not 的子字符串强>等于FOO;并用格式“(inner substring)”替换整个子字符串。以下将匹配:

  • BEGIN_bar_END -> (bar)
  • BEGIN_buz_END -> (buz)
  • BEGIN_ihfd8f398IHFf9f39_END -> (ihfd8f398IHFf9f39)

BEGIN_FOO_END 不匹配。

我尝试过以下方法,但似乎找不到正确的语法:

sed -e 's/BEGIN_(^FOO)_END/($1)/g'
sed -e 's/BEGIN_([^FOO])_END/($1)/g'
sed -e 's/BEGIN_(?!FOO)_END/($1)/g'
sed -e 's/BEGIN_(!FOO)_END/($1)/g'
sed -e 's/BEGIN_(FOO)!_END/($1)/g'
sed -e 's/BEGIN_!(FOO)_END/($1)/g'

【问题讨论】:

标签: regex sed


【解决方案1】:

sed,IIRC 中没有通用的否定运算符,因为编译带有对 DFAs 的否定的正则表达式需要指数时间。你可以解决这个问题

'/BEGIN_FOO_END/b; s/BEGIN_\(.*\)_END/(\1)/g'

其中/BEGIN_FOO_END/b 表示:如果我们找到BEGIN_FOO_END,则分支(跳转)到sed 脚本的末尾。

【讨论】:

  • 也可以写成sed '/BEGIN_FOO_END/!s/BEGIN_\(.*\)_END/(\1)/g'
  • 我想指出sed '/BEGIN_FOO_END/!s|BEGIN_\(.*\)_END|(\1)|g' 有效,但sed '|BEGIN_FOO_END|!s|BEGIN_\(.*\)_END|(\1)|g' 无效!显然,它允许您在后一部分中替换与“/”不同的分隔符,但在第一部分中则不行。很奇怪。
  • @CommaToast s/// 命令可以使用任意分隔符;地址不能。
  • 地址分隔符可以是任意的,但第一个分隔符必须转义,例如:printf '%s\n' a b c | sed '\|a|,\|b|d' - 使用带有--posix 选项的 GNU sed 测试。
  • 感谢 DFA 链接!
【解决方案2】:

这个话题可能有点老了,但为了完整起见,否定运算符!怎么样:

让所有的不开心变成非常开心:

echo -e 'happy\nhappy\nunhappy\nhappy' | sed '/^happy/! s/.*/VERY HAPPY/'

在这里找到这个:How to globally replace strings in lines NOT starting with a certain pattern

【讨论】:

  • 我总是在看到与 sed 相关的东西后去 grymoire。我检查了你的,它就在我的鼻子下面
【解决方案3】:

这可能对你有用:

sed 'h;s/BEGIN_\(.*\)_END/(\1)/;/^(FOO)$/g' file

这只有在每行只有一个字符串时才有效。

对于每行多个字符串:

sed 's/BEGIN_\([^F][^_]*\|F[^O][^_]*\|FO[^O][^_]*\|FOO[^_]\+\)_END/\(\1\)/g' file

或者更容易理解的:

sed 's/\(BEGIN_\)FOO\(_END\)/\1\n\2/g;s/BEGIN_\([^\n_]*\)_END/(\1\)/g;s/\n/FOO/g' file

【讨论】:

    【解决方案4】:

    我不知道一个漂亮的方法,但你总是可以这样做:

    $ cat file
    BEGIN_FOO_END
    BEGIN_FrOO_END
    BEGIN_rFOO_END
    $ sed '/BEGIN_FOO_END/ !{s/BEGIN_\([^_]*\)_END/(\1)/}' file 
    BEGIN_FOO_END
    (FrOO)
    (rFOO)
    

    【讨论】:

      猜你喜欢
      • 2016-07-05
      • 2012-11-04
      • 1970-01-01
      • 1970-01-01
      • 2012-12-13
      • 1970-01-01
      • 1970-01-01
      • 2019-04-17
      相关资源
      最近更新 更多