递归正则表达式来处理由{|括起来的嵌套字符串和|}

时间:2009-12-14 04:21:17

标签: php regex recursion

在一个项目中,我有一个包含这样的模式的文本:

{|文字{| text |} text |}
更多文字

我想用括号获得第一部分。为此我递归地使用preg_match。以下代码已经正常工作:

preg_match('/\{((?>[^\{\}]+)|(?R))*\}/x',$text,$matches);

但如果我添加符号“|”,我得到一个空的结果,我不知道为什么:

preg_match('/\{\|((?>[^\{\}]+)|(?R))*\|\}/x',$text,$matches);

我无法使用第一个解决方案,因为在文本中也可能存在类似{text}的内容。谁能告诉我这里做错了什么? THX

3 个答案:

答案 0 :(得分:3)

试试这个:

'/(?s)\{\|(?:(?:(?!\{\||\|\}).)++|(?R))*\|\}/'

在原始正则表达式中,您使用字符类[^{}]来匹配除分隔符之外的任何内容。当分隔符只有一个字符时,这很好,但是你的字符是两个字符。要不匹配多字符序列,您需要以下内容:

(?:(?!\{\||\|\}).)++

点匹配任何字符(包括换行符,感谢(?s)),但只有在前瞻确定它不属于{||}序列之后。我也删除了你的原子组((?>...))并用占有量词(++)替换它以减少混乱。但是你绝对应该在正则表达式的那一部分中使用其中一个来阻止catastrophic backtracking

答案 1 :(得分:1)

您对正则表达式有一些建议,但如果您想知道原始正则表达式失败的原因,请继续阅读。当匹配关闭“|}”标签时,问题就出现了。 (?>[^{}]+)(或[^{}]++)子表达式将匹配“|”,导致|}子表达式失败。由于子表达式没有回溯,因此无法从失败的匹配中恢复。

答案 2 :(得分:0)

请参阅PHP - help with my REGEX-based recursive function

使其适应您的使用

preg_match_all('/\{\|(?:^(\{\||\|\})|(?R))*\|\}/', $text, $matches);