Regexp,跳过嵌套对

时间:2011-03-28 10:51:15

标签: regex

在我自己的标记语言中,我有引号标记>>which use these characters to make a blockquote<<。当存在嵌套的blockquote时,问题就开始了:

>>(1)
start1
  >>(2)quote 2!<<(3)
<<(4)

我想只匹配最外面的标签,例如:

<blockquote>
start1
  >>quote 2!<<
</blockquote>

如果我尝试一个简单的不正确的正则表达式/>>(.+?)<</,(1)和(3)将匹配,(2)和(4)将不会匹配。如果我不成功/>>(.+)>>/(1)和(4)将成功匹配(并通过递归调用函数,然后我可以匹配(2)与(3)),但它将无法工作,当我有同一段文字中的两个街区:

>>(A)quote1<<(B)

>>(C)quote2<<(D)

贪婪者将(A)与(D)匹配,仅留下(B)和(C)。我想我必须以某种方式使它“不合适,但只有在里面没有其他配对”,这超出了我的技能。有没有办法让它正常工作?那么(1)匹配(4),(A)匹配(B)和(C)匹配(D)?如果你能想到非正则表达式解决方案(但不是解析器)那么它对我来说也足够好了。我不是要问如何进行(2)匹配(3),如何成功跳过它们(或任何其他嵌套对)。

成功!受到Arjen建议的启发,我最终使用了这样的结构(不一定有效:

$text = str_replace('([^>]|^)>([^>]|$)', '$1&gt;$2', $text);
while ($len != strlen($text)){
    $len = strlen($text);
    $text = preg_replace_callback('/>>([^>]+?)<</', "blockHashFunction", $text);
}

即。我首先编码所有单个&gt;然后执行递归preg_replace。在这种情况下散列意味着>>asdsad<<被替换为,例如"\xFE:3:\xFE",在脚本的末尾它没有被散列(好吧,更像是实际上解码,我猜)到正确的{{} 1}}。

1 个答案:

答案 0 :(得分:2)

正则表达式并不适合这种解析。实际上有一些RegEx引擎支持嵌套/平衡匹配,比如.NET Framework RegEx引擎(参见:http://blogs.msdn.com/b/bclteam/archive/2005/03/15/396452.aspx)。但是,我觉得这会导致非常复杂的模式。

如果您创建与开始或结束标记匹配的正则表达式并手动创建所有匹配的树,则会更好。处理完整个字符串后,您可以从生成的集合中丢弃不需要的匹配项。