需要一个正则表达式专家来匹配嵌套括号

时间:2015-04-13 11:59:50

标签: php regex recursion

字符串:

Démontrer par récurrence que pour tout entier naturel n,

\(\displaystyle{1^2+2^2+\ldots+n^2=\sum_{k=0\dfrac dsdq ds}rr^{n}k^2=\dfrac{n(n+1)(2n+1)}{6}}\)

Démontrer par récurrence que pour tout entier naturel n,

\(\displaystyle{1^2+2^2+\ldots+n^2=\sum_{k=0\dfrac{test} fdfd}^{n}k^2=\dfrac{n(n+1)(2n+1)}{6}}\)

我需要在_ {...}或^ {...}

中用\ frac替换\ dfrac

我尝试了很多模式(徒劳),如:

/(_|\^)\{(.*[^{}])(\\dfrac)(.*[^{}])}/gU

2 个答案:

答案 0 :(得分:3)

您需要使用preg_replace_callback,其模式能够使用嵌套的大括号在_{}^{}之间提取内容,以及一个回调函数将替换匹配中出现的所有\dfrac。例如:

$pattern = '~[_^]({[^{}]*(?:(?1)[^{}]*)*})~';

$result = preg_replace_callback($pattern,
    function ($m) { return str_replace('\dfrac', '\frac', $m[0]); },
    $text);

模式细节:

~              # pattern delimiter
[_^]           # _ or ^
(              # open the capture group 1
    {
    [^{}]*     # all that is not a curly bracket
    (?:        # open a non capturing group
        (?1)   # the recursion is here:
               # (?1) refers to the subpattern contained in capture group 1
               # (so the current capture group)
        [^{}]* # 
    )*         # repeat the non capturing group as needed
    }
)              # close the capture group 1
~

注意:如果花括号并不总是平衡,您可以将量词更改为占有,以防止过多的回溯并使模式更快地失败:

$pattern = '~[_^]({[^{}]*+(?:(?1)[^{}]*)*+})~';

或者您也可以使用原子组(或更好):

$pattern = '~[_^]({(?>[^{}]*(?:(?1)[^{}]*)*)})~';

答案 1 :(得分:2)

你可以试试这个正则表达式:

(?(DEFINE)                            # Definitions
(?<needle>\\dfrac(?=[^\}]*\}))    # What to search for
(?<skip>^[^\{]*\{|\}[^\{]*\{)               # What we should skip
)
(?&skip)(*SKIP)(*FAIL)                # Skip it
|
(?&needle)                            # Match it

请参阅demo

PHP代码:

$re = "/(?(DEFINE)                            # Definitions
        (?<needle>\\\\dfrac(?=[^\\}]*\\}))    # What to search for
        (?<skip>^[^\\{]*\\{|\\}[^\\{]*\\{)               # What we should skip
        )
        (?&skip)(*SKIP)(*FAIL)                # Skip it
        |
        (?&needle)                            # Match it/xm"; 
$str = "Démontrer par récurrence que pour tout entier naturel n,\n\dfrac\n\(\displaystyle{1^2+2^2+\ldots+n^2=\sum_{k=0\dfrac dsdq ds}rr^{n}k^2=\dfrac{n(n+1)(2n+1)}{6}}\)\nDémontrer par récurrence que pour tout entier naturel n,\n\n\(\displaystyle{1^2+2^2+\ldots+n^2=\sum_{k=0\dfrac{test} fdfd}^{n}k^2=\dfrac{n(n+1)(2n+1)}{6}}\)\n\n\dfrac"; 
$subst = "\\frac"; 
$result = preg_replace($re, $subst, $str);