0

我正在使用 GNU sed 4.2.1 版,我正在尝试编写一个非贪婪的 SED 正则表达式来提取一个由其他两个字符串分隔的字符串。当分隔字符串是单字符时,这很容易:

s:{\([^}]*\)}:\1:g

在该示例中,字符串由左侧的“{”和右侧的“}”分隔。

如果分隔字符串是多个字符,比如 '{{{' 和 '}}}',我可以像这样调整上面的表达式:

s:{{{\([^}}}]*\)}}}:\1:g

所以中心表达式匹配任何不包含'}}}'结束字符串的东西。但这仅在匹配字符串根本不包含 '}' 时才有效。就像是:

{{{cannot match {this broken} example}}}

不会工作,但

{{{can match this example}}}

确实有效。当然

s:{{{\(.*\)}}}:\1:g

总是有效但很贪心,因此不适合在同一行出现多个模式的情况。

我理解除此之外的[^a]任何东西a和除此之外的任何[^ab]东西,尽管它似乎有效,但我认为这不是排除 3 个连续字符序列的正确方法。ab[^}}}]

那么如何为 SED 编写一个匹配一个由其他两个字符串分隔的字符串的正则表达式?

4

2 回答 2

1

你是对的,那[^}}}]是行不通的。否定字符类匹配不是其中一个字符的任何内容。重复字符不会改变逻辑。所以你写的和[^}]. (当表达式中没有大括号时,很容易理解为什么这会起作用)。

在 Perl 和兼容的正则表达式中,您可以使用?a*或非+贪婪:

 s:{{{(.*?)}}}:$1:g

这将始终匹配}}}打开后的第一个{{{

但是,这在 Sed 中是不可能的。事实上,我不认为 Sed 有任何方法可以进行这种匹配。唯一的其他方法是使用 Sed 也没有的高级功能,例如前瞻。

您可以通过选项轻松地以类似 sed 的方式使用 Perl -pe,这会导致它从命令行 ( -e) 获取一行代码并自动遍历每一行并打印结果 ( -p)。

perl -pe 's:{{{(.*?)}}}:$1:g'

文件的-i就地编辑选项也很有用,但首先要确保您的正则表达式是正确的!

有关详细信息,请参阅perlrun

于 2013-03-05T12:17:30.340 回答
0

sed可以这样做:

sed -e :a -e 's/\(.*\){{{\(.*\)}}}/\1\2/ ; ta'

和:

{{{can match this example}}} {{{can match this 2nd example}}}

这给出了:

can match this example can match this 2nd example

这不是惰性匹配,而是通过从右到左替换我们可以利用 sed 的贪心。

于 2013-03-05T14:26:26.617 回答