我处理的字符串如下所示:
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);
另一种选择是只替换匹配的{
and }
,但是你必须重复这样做,因为一次调用preg_replace
不能替换多个嵌套级别:
do
{
$str = preg_replace('/\{([^{]*?)\}/', '<tag>$1</tag>', $str, -1, $count);
}
while ($count > 0)
编辑:虽然 PCRE 支持递归,(?R)
但这很可能无助于替换。原因是,如果一个捕获组被重复,它的引用将只包含最后一个捕获(即当匹配/(a|b)+/
in时aaaab
,$1
将包含b
)。我想这对于递归是一样的。这就是为什么你只能替换最里面的匹配,因为它是递归中捕获组的最后一个匹配。同样,您不能尝试使用递归捕获{
并}
替换它们,因为它们也可能匹配任意次数,并且只会替换最后一个匹配项。
Just matching a correct nested syntax and then replacing the innermost or outermost matching brackets will not help either (with one preg_replace
call), because multiple matches will never overlap (so if 3 nested brackets have been found, the inner 2 brackets themselves will be disregarded for further matches).
两个步骤怎么样:
s!{!<tag>!g;
s!}!</tag>!g;
(perl 格式;根据需要转换为您的格式)
或者这个:
1 while s!{([^{}]*)}!<tag>$1</tag>!g;