Необязательная группа в регулярном выражении PHP preg_match_all () всегда игнорируется - PullRequest
0 голосов
/ 11 августа 2011

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

Это оригинальное регулярное выражение, которое работает:

$regex = "~:begin(.*)[\r\n]+:desc(.*)[\r\n]+(.*)[\r\n]+:end(?:.*)[\r\n]+~msU";
preg_match_all($regex, $text, $matches);

Это текст, который анализируется:

  :begin test
  :desc testing
  some code
  more code
  last code
  :end test

  :begin test2
  :desc testing2
  some code2
  last code2
  :end test2

Это регулярное выражение правильно анализирует строки, начинающиеся с ": desc", в егособственной группы, но когда я делаю строку ": desc" необязательной, эта же группа всегда пуста, и вместо этого строка добавляется в следующую группу в начале блока "code".

Этоскорректированное регулярное выражение с необязательной группой для desc:

$regex = "~:begin(.*)[\r\n]+(:desc(.*)[\r\n]+)?(.*)[\r\n]+:end(?:.*)[\r\n]+~msU";

Мне кажется, я понимаю, что происходит, но не то, почему или как решить проблему.Понятно, что поскольку в начале блока кода нет какого-то определенного маркера, когда предыдущая строка становится необязательной, регулярное выражение обходит необязательную группу и объединяет все это с последующим блоком кода.Я пытался играть с флагами, меняя группы на все виды комбинаций жадных / не жадных, но не вставляя что-то вроде префикса ": code", чтобы указать начало следующего блока, я просто не могу остановитьсярегулярное выражение от размещения необязательной строки в блоке кода после него.

Я просто хочу иметь возможность сделать необязательный оператор однострочный: desc без добавления дополнительных тегов или разделителей к данным.

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

1 Ответ

1 голос
/ 11 августа 2011

Отрицательный взгляд может помочь здесь:

~:begin (.*)[\r\n]+(?::desc (.*)[\r\n]+)?^(?!:desc)(?:(.*)[\r\n]+)?:end(?:.*)[\r\n]+~msU

Основная часть, которая была добавлена: ^(?!:desc) - это проверит, что следующая строка не начинается с : desc

Я также добавил (?:...) для необязательных групп, чтобы они не захватывались для массива результатов. При необходимости удалите их.

Что именно делает негативный взгляд? Основная проблема с многострочным и (. ) * в том, что точка соответствует (почти!) Любому символу. И почти означает, за исключением новой строки ( Подробности ). Но поскольку ваше регулярное выражение использует «многострочный режим», это усложняет задачу.

Давайте разберем ваше второе регулярное выражение на более мелкие части:

:begin(.*)[\r\n]+ Эта часть просто находит первую строку. Я только добавил пробел, чтобы исключить его из результата.

(:desc(.*)[\r\n]+)? Это ваша оригинальная дополнительная партия, которая должна найти вторую строку. Здесь также добавлено место.

(.*)[\r\n]+ Это сторона кода, но в вашем случае это была жадная сторона, поэтому она также нашла необязательную сторону для : desc Чтобы изменить это, отрицательный взгляд исключил эту часть, и поскольку вы хотели изменить это значение на необязательное, оно было изменено на: ^(?!:desc)(.*)[\r\n]+ - «^» также убедился, что это начало новой строки.

:end(?:.*)[\r\n]+ Никаких изменений здесь не требуется.

Дополнительные улучшения

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

~:begin ([^$]*)(?::desc([^$]*))?^(?!:desc)(?:([^$]*))?:end+~msU

Этот код использует «$» для проверки конца каждой строки, поэтому вам больше не нужно проверять символы новой строки.

...