2013-06-22 2 views
5

Честно говоря, я думаю, что сначала я должен попросить о помощи с синтаксисом этого вопроса.Как создать цикл с регулярным выражением?

Но, пожалуйста, если вы понимаете, что я имею в виду, отредактируйте название с подходящим.

Есть ли способ сделать шаблон, который может разделить текст следующим образом.

{{START}} 
    {{START}} 
     {{START}} 
      {{START}} 
      {{END}} 
     {{END}} 
    {{END}} 
{{END}} 

Таким образом, каждый {{START}} соответствует его {{END}} изнутри сначала во внешний последний!

И если я не могу сделать это только с регулярным выражением. Как это сделать с помощью PHP?

спасибо, что посмотрели.

+5

Это не может быть сделано с большинством вариантов регулярного выражения, хотя есть трюки, за пределами моего ken, которые делают возможным использование таких языков, как Perl. Читайте о лемме о перекачке, чтобы узнать, почему вы не можете этого сделать. – siride

+0

Я предполагаю, что ваше форматирование какого-то входа. Если вы объясните немного больше, возможно, будет предложен альтернативный подход. –

+0

Похоже, вы пытаетесь что-то разобрать ... [Если что-то находится рядом с таким сложным, как HTML (выглядит так для меня), делать это с помощью регулярных выражений - плохая идея.] (Http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contains-tags/1732454 # 1732454) – michaelb958

ответ

4

Это не возможность регулярного выражения, которое может анализировать только обычные грамматики. То, что вы описываете, потребует автомата pushdown (обычные языки определяются regular automaton).

Вы можете использовать регулярное выражение для анализа отдельных элементов, но часть «глубина» должна обрабатываться языком с понятием памяти (PHP для этого подходит).

Так что в вашем решении регулярные выражения будут использоваться только для идентификации ваших тегов, в то время как реальная логика относительно глубины отслеживания и определения того, к какому элементу принадлежит тег END, должна быть вашей самой программой.

+1

PHP использует механизм регулярных выражений, который может быть больше, чем просто регулярные выражения. http://pcre.org/pcre.txt - так что ваш ответ - только академический, а не практический вопрос. Однако вы также можете использовать этот движок, чтобы выполнить его. Только первая часть не относится к PHP/PCRE. – hakre

1

Вы не можете сделать это с помощью чистого RegEx, однако с помощью простой петли это может быть выполнено.

JS Пример:

//[.\s\S]* ensures line breaks are matched (dotall not supported in JS) 
var exp = /\{\{START\}\}([.\s\S]*)\{\{END\}\}/; 

var myString = "{{START}}\ntest\n{{START}}\ntest 2\n{{START}}\ntest 3\n{{START}}\ntest4\n{{END}}\n{{END}}\n{{END}}\n{{END}}"; 

var matches = []; 
var m = exp.exec(myString); 
while (m != null) { 
    matches.push(m[0]); 
    m = exp.exec(m[1]); 
} 

alert(matches.join("\n\n")); 

PHP (я понятия не имею, если это правильно, это было навсегда, так как я сделал PHP)

$pattern = "/\{\{START\}\}([.\s\S]*)\{\{END\}\}/"; 
$myString = "{{START}}\ntest\n{{START}}\ntest 2\n{{START}}\ntest 3\n{{START}}\ntest4\n{{END}}\n{{END}}\n{{END}}\n{{END}}"; 

$result = preg_match($pattern, $myString, $matches, PREG_OFFSET_CAPTURE); 
$outMatches = array(); 
while ($result) { 
    array_push($outMatches, $matches[0]); 
    $result = preg_match($pattern, $matches[1], $matches, PREG_OFFSET_CAPTURE); 
} 
print($outMatches); 

Выход:

{{START}} 
test 
{{START}} 
test 2 
{{START}} 
test 3 
{{START}} 
test4 
{{END}} 
{{END}} 
{{END}} 
{{END}} 

{{START}} 
test 2 
{{START}} 
test 3 
{{START}} 
test4 
{{END}} 
{{END}} 
{{END}} 

{{START}} 
test 3 
{{START}} 
test4 
{{END}} 
{{END}} 

{{START}} 
test4 
{{END}} 
+0

OP нуждался в решении PHP. Попробуй еще раз. – michaelb958

+0

Добавлен PHP, не знаю, правильно это или нет. Не делал PHP за многие годы. –

+0

В PHP regex есть рекурсия, см. Http://pcre.org/ – hakre

2

Можно! Вы можете иметь каждый уровень содержания с использованием рекурсивного регулярного выражения:

$data = <<<LOD 
{{START1}} 
    aaaaa 
    {{START2}} 
     bbbbb 
     {{START3}} 
      ccccc 
      {{START4}} 
       ddddd 
      {{END4}} 
     {{END3}} 
    {{END2}} 
{{END1}} 
LOD; 

$pattern = '~(?=({{START\d+}}(?>[^{]++|(?1))*{{END\d+}}))~'; 
preg_match_all ($pattern, $data, $matches); 

print_r($matches); 

объяснение:

часть: ({{START\d+}}(?>[^{]++|(?1))*{{END\d+}})

Эта часть шаблона описывает вложенную структуру с {{START#}} и {{END#}}

(   # open the first capturing group 
{{START\d+}} 
(?>   # open an atomic group (= backtracks forbidden) 
    [^{]++ # all that is not a { one or more times (possessive) 
    |   # OR 
    (?1)  # refer to the first capturing group itself 
)    # close the atomic group 
{END\d+}}  # 
)    # close the first capturing group 

Теперь проблема в том, что вы не можете захватить весь уровень только этой частью, потому что все символы строки потребляются шаблоном. Другими словами, вы не можете совместить перекрывающиеся части строки.

Проблема заключается, чтобы обернуть всю эту часть внутри нулевой шириной утверждения, которое не потребляют символы как опережающий просмотр (?=...), результат:

(?=({{START\d+}}(?>[^{]++|(?1))*{{END\d+}})) 

Это будет соответствовать всем уровням.