正则表达式 - 嵌套模式 - 在外部模式中但排除内部模式

时间:2011-06-07 20:36:09

标签: regex bash sed grep pattern-matching

我有一个包含以下内容的文件。

<td> ${ dontReplaceMe } ReplaceMe ${dontReplaceMeEither} </td>

如果它在td标记中,我想匹配'ReplaceMe',但如果它在$ {...}表达式中则不匹配。

我可以使用正则表达式吗?

目前有:

sed '/\${.*?ReplaceMe.*?}/!s/ReplaceMe/REPLACED/g' data.txt

5 个答案:

答案 0 :(得分:9)

这是不可能的。

正则表达式可用于 Type-3 Chomsky语言(常规语言)。
但是,您的示例代码是 Type-2 Chomsky语言(无上下文语言)。

几乎只要涉及任何类型的嵌套(括号),您就会处理无上下文的语言,这些语言不包括在正则表达式中。

基本无法在正则表达式中定义within a pair of x and y ,因为这会需要常规表达式有某种堆栈,它不是(在功能上等同于有限状态自动机)。


被brandizzi挑战,找到一个可能至少与琐碎案件相匹配的正则表达式
我实际上想出了这个(痛苦的hacky)正则表达式模式:

perl -pe 's/(?<=<td>)((?:(?:\{.*?\})*[^{]*?)*)(ReplaceMe)(.*)(?=<\/td>)/$1REPLACED$3/g'

对于这些情况做正确的 (sic!) 匹配

<td> ${ dontReplaceMe } ReplaceMe ${dontReplaceMeEither} </td>
<td> ReplaceMe ${dontReplaceMeEither} </td>
<td> ${ dontReplaceMe } ReplaceMe </td>
<td> ReplaceMe </td>

失败了 (嵌套是Chomsky Type-2,还记得吗?;))

<td>${ ${ dontReplaceMe } ReplaceMe ${dontReplaceMeEither} }</td>

无法替换多个匹配

<td> ReplaceMe ReplaceMe </td>
<td> ReplaceMe ${dontReplaceMeEither} ReplaceMe </td>

获得领先的$是最棘手的部分 这使得Reginald / Reggy在写这个野兽时不断崩溃。

再次:实验,不要在生产代码中使用它!

(...或者我会追捕你,我是否必须使用您的代码/应用程序;)

答案 1 :(得分:1)

嗯,对于这种简单的情况,您只需要验证 ${.*}

$ sed '/\${.*}/!s/ReplaceMe/REPLACED/' input
<td> REPLACED </td>
<td> ${ don't ReplaceMe } </td>

! sed地址之后的/\${.*}/会否定标准。

OTOH,如果情况不那么简单,我怀疑你的问题会增长很多,正则表达式不是最好的解决方案。

答案 2 :(得分:1)

通常在涉及结构化标记时使用正则表达式是个坏主意。在某些特殊情况下它可能没问题,但有更好的工具来解析html和然后你可以在文本节点上使用正则表达式。

答案 3 :(得分:0)

<td>.*(?<!${).*ReplaceMe(?!.*}).*</td>这样的东西应该有效,如果grep支持负面的看守(我不记得是否会这样做)。

答案 4 :(得分:0)

sed -i 's/<td>\sReplaceMe\s<\/td>/<td>Replaced<\/td>/gi' input.file

为我工作。

如果出现错误,您可以考虑使用-i.bak备份旧文件。

或者,

perl -pi -e 's/<td>\sReplaceMe\s<\/td>/<td>Replaced<\/td>/g' temp

也可以,再次注意-pi.bak备份。