Рекурсивният регулярен израз не съответства на шаблонни блокове

Опитвам се да разбера повече за регулярния израз и в този случай рекурсията, която можете да направите в регулярен израз.

Опитвам се да съпоставя вложен блок от {foreach $VAR} ... {/foreach}. Но по някаква причина моят регулярен израз не съвпада и не разбирам защо.

Надявах се, че някой тук може да хвърли малко светлина върху това. Азне се интересувам от бърза корекция на регулярен израз. Но всъщност по-скоро защо моят регулярен израз не прави това, което очаквам. Какво точно се случва?

Това е кодът, който имам:

<?php
$str = 'start of text
{foreach $ABC}
  in 1st loop
  {foreach $XYZ}
    in 2nd loop
  {/foreach}
{/foreach}
some other stuff';

if ( preg_match ( '#{foreach \$.*?}((?!foreach)|(?R))*{/foreach}#', $str, $matches ) )
{
    print_r($matches);
}
else
{
    echo 'No match';
}

Ето разбивката на моя регулярен израз как мисля, че работи:

{foreach \$     #match literally "{foreach $"
.*?}            #followed by any character ending with a '}'
(               # start a group
  (?!foreach)   # match any character, aslong as it's not the sequence 'foreach'
  |             # otherwise
  (?R)          # do a recursion
)               # end of group
*               # match 0 or more times with a backtrace...
{/foreach}      # ...backtracing until you find the last {/foreach}

Ето как мисля, че регулярният израз работи. Но очевидно не е така. Та въпросът ми е къде греша в обяснението си?

Можете да си поиграете с този код тук: http://codepad.viper-7.com/508V9w


Само да поясня.

Опитвам се да получа съдържанието на всеки foreach блок. Така че в моя случай:

arr[0] => in 1st loop
      {foreach $XYZ}
        in 2nd loop
      {/foreach}
arr[1] => in 2nd loop

OR -

arr[0] => {foreach $ABC}
      in 1st loop
      {foreach $XYZ}
        in 2nd loop
      {/foreach}
    {/foreach}
arr[1] => {foreach $XYZ}
        in 2nd loop
      {/foreach}

И двете ще се справят добре.


person w00    schedule 18.03.2013    source източник
comment
Компилира ли се този модел? { и } са специални знаци в областта на регулярните изрази.   -  person Kenneth K.    schedule 18.03.2013
comment
@КенетК. Да, изглежда, че се компилира добре. Също така не виждам разлика, когато им избягам. Но може би е по-добре за мен да правя това от сега.   -  person w00    schedule 18.03.2013


Отговори (1)


Първо, . съвпада с всичко освен нови редове по подразбиране. За да съвпада и с нов ред, трябва да зададете модификатора s.

И второ, вие използвате твърдения тук: ((?!foreach)|(?R))*, но няма действителни знаци, които да съответстват. Имате нужда от поне точка преди квантора * или нещо подобно.

#{foreach \$.*?}((?!foreach)|(?R)).*{/foreach}#s дава следния резултат с вашия тестов текст:

Array
(
    [0] => {foreach $ABC}
  in 1st loop
  {foreach $XYZ}
    in 2nd loop
  {/foreach}
{/foreach}
    [1] => 
)
person CBroe    schedule 18.03.2013
comment
Забравих да добавя модификатора s в публикацията си. Но както можете да видите, той е там в страницата codepad. Добавяйки . преди звездичките, това наистина ми дава резултата, който показвате. Но как така не улавя вътрешното {foreach $XYZ}? Надявах се този регулярен израз да може да направи това. Също така не съм сигурен откъде идва празният мач [1], някакви идеи? - person w00; 18.03.2013
comment
Няма прихващане, защото не сте задали подходящи скоби за прихващане около подмодела. - person CBroe; 18.03.2013