Разбор блока с помощью регулярного выражения php

#php #regex #block

#php #регулярное выражение #блок

Вопрос:

Я пытаюсь написать (я думаю) довольно простое регулярное выражение с помощью PHP, но это не работает. В принципе, у меня есть блок, определенный следующим образом:

 %%%%blockname%%%%
stuff goes here
%%%%/blockname%%%%
  

Я не силен в регулярных выражениях, но это то, что я пробовал:

 preg_match_all('/^%%%%(.*?)%%%%(.*?)%%%%/(.*?)%%%%$/i',$input,$matches);
  

Он возвращает массив с 4 пустыми записями.

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

Пожалуйста, просветите меня 🙂

Комментарии:

1. Если у вас нет вложенных блоков, вам не нужно беспокоиться о том, что третье совпадение совпадает с первым. С другой стороны, если у вас есть вложенные блоки, регулярные выражения могут оказаться неподходящим вариантом..

2. У меня нет вложенных блоков прямо сейчас, но могут появиться в будущем. Я также думал о том, чтобы, возможно, использовать вместо этого анализатор HTML и определять блоки, предоставляя атрибуты моему HTML-коду.

Ответ №1:

Вам нужно разрешить совпадение точки с новой строкой и разрешить совпадение ^ и $ в начале и конце строк (а не только всей строки):

 preg_match_all('/^%%%%(.*?)%%%%(.*?)%%%%/(.*?)%%%%$/sm',$input,$matches);
  

s (Однострочный) параметр позволяет использовать точку в соответствии с любым символом, включая новые строки.

m (Многострочный) параметр позволяет ^ и $ совпадать в начале и в конце строк.

i Опция не нужна в вашем регулярном выражении, поскольку в нем нет символов, чувствительных к регистру.

Затем, чтобы ответить на вторую часть вашего вопроса: если blockname в обоих случаях одно и то же, то вы можете сделать это явным, используя обратную ссылку на первую группу захвата:

 preg_match_all('/^%%%%(.*?)%%%%(.*?)%%%%/1%%%%$/sm',$input,$matches);
  

Комментарии:

1. Хороший момент, хотя на самом деле это не ответ на вопрос Кокоша.

2. Я полагаю, 1 тогда имеется в виду первый матч, учись чему-то каждый день 🙂

3. n относится к содержимому n -й группы захвата (набор круглых скобок) в регулярном выражении. В другом комментарии вы упомянули, что в будущем у вас могут появиться вложенные блоки. Здесь все становится сложнее. Это можно сделать, но это, мягко говоря, сложно.

4. Я обнаружил проблему с моим вводом HTML, %%%%blockname%%%% был сделан отступ, поэтому, я думаю, ^ не разрешил сопоставлять его, потому что это не было первым в строке.

5. В этом случае просто добавьте s* после ^ и / или перед $ .

Ответ №2:

Я почти уверен, что вы не можете, поскольку для этих операций потребуется сохранить переменную, а вы не можете в регулярном выражении. Вам следует попробовать сделать это с помощью встроенного в PHP анализатора токенов. http://php.net/manual/en/function .token-get-all.php

Комментарии:

1. что вы имеете в виду, что вы не можете сохранить переменную в регулярном выражении? Я не думаю, что я что-то упускаю, когда говорю, что $matches будет содержать то, что соответствует.

2. $matches является PHP. Но если вы не хотите использовать regex для сопоставления открывающего и закрывающего тегов, вам придется сохранить первый тег и выполнить поиск только по соответствующему закрывающему тегу (вместо любого закрывающего тега).

3. Я не уверен, что я вас неправильно понял, но ответ, который дал Тим Пьецкер, действительно позволяет мне сопоставлять открывающий и закрывающий теги в одном регулярном выражении (и я не могу понять, почему это не должно быть возможно в первую очередь).

4. Пожалуйста, перечитайте вопрос. Он запрашивает регулярное выражение, которое может обнаружить соответствующий (вложенный) закрывающий тег. (пример: <a> ... </a> , <a> ... <b> ... </b> ... </a> , выдал бы a ... b вместо b ... b ... a ... a )