在一个项目中,我有一个包含这样的模式的文本:
{|文字{| text |} text |}
更多文字
我想用括号获得第一部分。为此我递归地使用preg_match。以下代码已经正常工作:
preg_match('/\{((?>[^\{\}]+)|(?R))*\}/x',$text,$matches);
但如果我添加符号“|”,我得到一个空的结果,我不知道为什么:
preg_match('/\{\|((?>[^\{\}]+)|(?R))*\|\}/x',$text,$matches);
我无法使用第一个解决方案,因为在文本中也可能存在类似{text}的内容。谁能告诉我这里做错了什么? THX
答案 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);