2013-03-18 1 views
2

Я пытаюсь понять больше о регулярном выражении, и в этом случае рекурсия вы можете сделать в регулярном выражении.Рекурсивное регулярное выражение, не соответствующее шаблонам блоков

Я пытаюсь сопоставить вложенный блок {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'; 
} 

Вот разбивка моего регулярного выражения, как, как я думаю, что это wokring:

{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 

ИЛИ -

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

Либо будет делать хорошо.

+0

компилировать ли эта схема? '{' и '}' являются специальными символами в земле регулярных выражений. –

+0

@ KennethK. Да, кажется, он компилируется отлично. Я также не вижу никакой разницы, когда я избегаю их. Но, может быть, мне лучше, если так или иначе. – w00

ответ

0

Прежде всего, . соответствует ничего, кроме новых строк по умолчанию. Чтобы он соответствовал символам новой строки, вы должны установить модификатор s.

А во-вторых, вы используете утверждения здесь: ((?!foreach)|(?R))*, но никаких фактических символов для соответствия. Вам нужна хотя бы точка перед квантором * или что-то в этом роде.

#{foreach \$.*?}((?!foreach)|(?R)).*{/foreach}#s дает следующий результат с тестовой текстом:

Array 
(
    [0] => {foreach $ABC} 
    in 1st loop 
    {foreach $XYZ} 
    in 2nd loop 
    {/foreach} 
{/foreach} 
    [1] => 
) 
+0

Я забыл добавить модификатор 's' в свой пост. Но, как видите, он находится на странице * codepad *. Добавляя '.' перед астериками, он действительно дает мне результат, который вы показываете. Но почему это не захватывает внутренний '{foreach $ XYZ}'? Я надеялся, что это регулярное выражение сможет это сделать. Также не знаете, где пустое совпадение происходит от '[1]', любых идей? – w00

+0

Нет захвата, потому что вы не установили соответствующие скобки для скобок вокруг подшаблона. – CBroe