Php 递归正则表达式不’;行不通

Php 递归正则表达式不’;行不通,php,regex,Php,Regex,我处理的字符串如下所示: abc {def ghi {jkl mno} pqr stv} xy z 我需要把括号中包含的数字放在标记中,所以看起来应该是这样的 abc <tag>def ghi <tag>jkl mno</tag> pqr stv</tag> xy z abc def ghi jkl mno pqr stv xy z 我试过了 '#(?<!\pL)\{ ( ([^{}]+) | (?R) )* \}(?!\pL)#x

我处理的字符串如下所示:

abc {def ghi {jkl mno} pqr stv} xy z
我需要把括号中包含的数字放在标记中,所以看起来应该是这样的

abc <tag>def ghi <tag>jkl mno</tag> pqr stv</tag> xy z
abc def ghi jkl mno pqr stv xy z
我试过了

'#(?<!\pL)\{  ( ([^{}]+) | (?R) )*  \}(?!\pL)#xu'
”#(?两个步骤如何:

s!{!!g;

s!}!!g;

(perl格式;根据需要翻译为您的格式)

或者可能是这样:


1而s!{([^{}]*)}!$1!g;

嵌套结构根据定义对于正则表达式来说太复杂了(是的,PCRE支持递归,但这对这个替换问题没有帮助)。有两种可能的选择(无论如何都要使用正则表达式)。首先,您可以简单地用开始标记替换开始括号,结束标记也是如此。但是,这也将转换不匹配的括号:

$str = preg_replace('/\{/', '<tag>', $str);
$str = preg_replace('/\}/', '</tag>', $str);
编辑:虽然PCRE支持使用
(?R)
递归,但这很可能无助于替换。原因是,如果重复捕获组,其引用将只包含最后一次捕获(即在
aaaaaab
中匹配
/(a | b)+/
时,
$1
将包含
b
)。我认为递归也是如此。这就是为什么您只能替换最里面的匹配项,因为它是递归中捕获组的最后一个匹配项。同样,您不能尝试捕获
{
}
使用递归并替换它们,因为它们也可能被匹配任意次数,并且只替换最后一个匹配


仅仅匹配一个正确的嵌套语法,然后替换最里面或最外面的匹配括号也不会有帮助(使用一个
preg_replace
call),因为多个匹配永远不会重叠(因此,如果找到了3个嵌套括号,则内部2个括号本身将被忽略以进行进一步的匹配).

已经考虑过了。它很简单,但如果找不到匹配的括号,可能会导致标记中断。您可以反复调用搜索/替换。(答案已更新)这就是
(?R)
所代表的含义。该定义仅在表达式为“正则表达式”时有效从数学意义上讲,PHP使用的.PCRE并不是任何想象中的规则:例如,您可以(像询问者那样)使用
(?R)
使表达式递归!现在,这是否是一个好主意是另一个问题,但它实际上不应该是不可能的。您是对的,PCRE支持
(?R)
但我似乎找不到任何(推荐的)将其用于
preg\u replace
的示例。它通常只用于
preg\u match
。我不知道。谢谢。@TikhonJelvis(当然还有@OP)我已经添加了一个解释,解释了为什么在这种情况下递归功能不能真正用于
preg\u replace
do
{
    $str = preg_replace('/\{([^{]*?)\}/', '<tag>$1</tag>', $str, -1, $count);
}
while ($count > 0)