PCRE (рекурсивный) шаблон, который соответствует строке, содержащей правильно заключенную в скобки подстроку. Почему этот провал? - PullRequest
3 голосов
/ 04 июня 2010

Ну, есть и другие способы (хммм ... или скорее рабочие способы) сделать это, но вопрос в том, почему этот отказывает?

/
\A              # start of the string
(               # group 1
(?:             # group 2
[^()]*          # something other than parentheses (greedy)
|               # or
\( (?1) \)      # parenthesized group 1
)               # -group 2
+               # at least once (greedy)
)               # -group 1
\Z              # end of the string
/x

Не соответствует строке с вложенными скобками: "(())"

Ответы [ 2 ]

7 голосов
/ 04 июня 2010

Это не сбой

$ perl junk.pl
matched junk >(())<

$ cat junk.pl
my $junk = qr/
\A              # start of the string
(               # group 1
(?:             # group 2
[^()]*          # something other than parentheses (greedy)
|               # or
\( (?1) \)      # parenthesized group 1
)               # -group 2
+               # at least once (greedy)
)               # -group 1
\Z              # end of the string
/x;

if( "(())" =~ $junk ){
    print "matched junk >$1<\n";
}
4 голосов
/ 06 июня 2010

Ух ты! .. Спасибо, барахло! Это действительно работает ... в Perl. Но не в PCRE. Итак, возникает вопрос: «В чем разница между сопоставлением регулярных выражений в Perl и PCRE?»

И вуаля! Есть ответ:

Отличие рекурсии от Perl

 In PCRE (like Python, but unlike Perl), a recursive subpattern call  is
 always treated as an atomic group. That is, once it has matched some of
 the subject string, it is never re-entered, even if it contains untried
 alternatives  and  there  is a subsequent matching failure.

Поэтому нам просто нужно поменять местами два подшаблона:

/ \A ( (?: \( (?1) \) | [^()]* )+ ) \Z /x

Спасибо!

...