我所处理的字符串如下:
abc {def ghi {jkl mno} pqr stv} xy z
我需要在标签中添加括号内的数字,应该像这样:
(数字)
。abc <tag>def ghi <tag>jkl mno</tag> pqr stv</tag> xy z
我已经尝试过了
'#(?<!\pL)\{ ( ([^{}]+) | (?R) )* \}(?!\pL)#xu'
但我得到的只是
<tag>xy z</tag>
。请帮忙,我做错了什么?嵌套结构对于正则表达式来说过于复杂(是的,PCRE支持递归,但这并不能解决替换问题)。有两种可能的选择(仍然使用正则表达式)。首先,您可以简单地将开放括号替换为开放标签,并对关闭标签进行相同的操作。然而,这样做也会将不匹配的括号转换:
$str = preg_replace('/\{/', '<tag>', $str);
$str = preg_replace('/\}/', '</tag>', $str);
{
和}
,但这会导致需要重复执行操作,因为一次preg_replace
调用无法替换多个嵌套级别:do
{
$str = preg_replace('/\{([^{]*?)\}/', '<tag>$1</tag>', $str, -1, $count);
}
while ($count > 0)
编辑:虽然PCRE支持使用(?R)
实现递归,但这很可能无法帮助替换。原因是如果捕获组重复,则其引用将仅包含最后一个捕获(例如在匹配/(a|b)+/
时,在aaaab
中,$1
将包含b
)。我猜递归也是如此。这就是为什么你只能替换最内层的匹配,因为它是递归内捕获组中的最后一次匹配。同样,您也不能尝试使用递归来捕获{
和}
并替换它们,因为它们也可能被匹配多次,只有最后一次匹配会被替换。
仅匹配正确嵌套的语法,然后替换最内部或最外部匹配的括号也没有作用(使用一个preg_replace
调用),因为多个匹配永远不会重叠(因此如果找到了3个嵌套的括号,内部的2个括号本身将被忽略以进行进一步的匹配)。
两步走怎么样:
s!{!<tag>!g;
s!}!</tag>!g;
(perl格式;根据需要将其转换为您的格式)
或者也可以这样:
1 while s!{([^{}]*)}!<tag>$1</tag>!g;
(?R)
的含义。 - tijagi(?R)
使表达式递归!现在,这是否是一个好主意是另一个问题,但它不应该是不可能的。 - Tikhon Jelvis(?R)
,但我似乎找不到任何(推荐的)使用它进行preg_replace
的例子。它通常似乎只用于preg_match
。 - Martin Enderpreg_replace
一起使用。 - Martin Ender