Сопоставление только кода php с использованием regex в глобальном многострочном режиме (/ gm)

Я пытаюсь сопоставить только код PHP, например код PHP в этом блоке:

<?php foo(); ?>

<abc>

<? foo(); ?>

<?php

foo();
bar();

?>

foo();
bar();

<? //also short open tag

foo();
bar();

?><?php

foo();
bar();

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

Я пробовал много вариантов регулярных выражений, в конце концов остановился на этом, но он явно не работает так, как я хочу, поскольку он находится в режиме /g, а также выбирает <abc>, хотя он не должен (Демо):

<\?.*[\s\S]*?(?:$|\?\>)

Есть ли способ добиться этого с помощью регулярного выражения в режиме /gm?

Обратите внимание, что причина, по которой я спрашиваю, заключается в том, что я использую программу поиска файлов, и когда я ищу содержимое многих файлов php, которые у меня есть, я хочу, чтобы он выполнял поиск только внутри кода php и не выдавал результатов, которые не имеют отношения . Поэтому я буду использовать это регулярное выражение как дополнительное условие к остальному поиску контента. Программа поиска использует режим PCRE /gm.

P.S. Прежде чем опубликовать вопрос, я провел много исследований по SO и не смог найти решения этого вопроса. Среди других вопросов я также проверил:

Мое регулярное выражение слишком много соответствует. Как мне это остановить?

Получить содержимое между двумя строками PHP

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

Вывод

В итоге я использовал решение Хулио и улучшил его, чтобы также учесть одинарные и двойные кавычки, как указано в примере в ответе Яна. Спасибо всем за ответы. Это последнее регулярное выражение, работающее в режиме /gm:

<\?[\s\S]*?(?:\z|\?\>|[\"\'].*?[\"\'][\s\S]*?\?>)

Демо

1
0
157
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Используйте это: <\?[\s\S]*?(?:\z|\?\>)

Демо

.*[\s\S]* избыточен. Вам просто нужен [\s\S]* для сопоставления любого символа (также, поскольку .* был жадным, он соответствовал вашему концу ?>)

Также используйте \z вместо $

Спасибо. Это в режиме /g, а не /gm

Nikita 웃 10.08.2018 15:10

Это должно сработать для вас:

(<\?)(.*?)(?:$|\?>)/isg

Онлайн-пример.

Спасибо. Это не режим /isg, если добавить m (многострочный) - не работает.

Nikita 웃 10.08.2018 15:11

Вы могли бы использовать

<\?(?:php)?        # <? or <?php
(?:(?!\?>)[\s\S])* # do not overrun ?> but match anything else greedily
(?:\?>)?           # ?> in the end

См. демо на regex101.com (обратите внимание на многословный флаг!).


Let me emphasize that this is generally a bad approach when it comes to e.g. strings such as
<?php
echo "This is hilarious ?>";
?>

См. Также демо для последнего на regex101.com. Здесь используйте синтаксический анализатор или переосмыслите исходную проблему.

Спасибо @Jan. Он почти готов, но не соответствует нижнему открытому блоку php.

Nikita 웃 10.08.2018 15:15

@CM 웃: Обновил, вставил закаленный жадный токен.

Jan 10.08.2018 15:22

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

Nikita 웃 10.08.2018 15:29

@CM 웃: В зависимости от вашей реальной проблемы вам также может потребоваться написать собственный парсер.

Jan 10.08.2018 15:31

Как это решение может также покрыть проблему кавычек? <\?[\s\S]*?(?:\z|\?\>|[\"\'].*?[\"\'][\s\S]*?\?>)

Nikita 웃 10.08.2018 16:17

Другие вопросы по теме