我工作的字符串看起来像这样:
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>
。求助,我做错了什么?
答案 0 :(得分:5)
根据定义,嵌套结构对于正则表达式来说太复杂了(是的,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个括号本身将被忽略以进一步匹配。)
答案 1 :(得分:3)
两个步骤怎么样:
s!{!<tag>!g;
s!}!</tag>!g;
(perl格式;视情况转换为您的格式)
或者这个:
1 while s!{([^{}]*)}!<tag>$1</tag>!g;