4

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

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>。请帮忙,我做错了什么?

4

2 回答 2

5

根据定义,嵌套结构对于正则表达式来说太复杂了(是的,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).

于 2012-10-12T17:31:10.993 回答
3

两个步骤怎么样:

s!{!<tag>!g;
s!}!</tag>!g;

(perl 格式;根据需要转换为您的格式)

或者这个:

1 while s!{([^{}]*)}!<tag>$1</tag>!g;

于 2012-10-12T17:23:10.643 回答