RegExp упражнение: неохотный квантификатор с прогнозным утверждением
Можете ли вы объяснить мне, как это работает? Вот пример:
<!-- The quick brown fox
jumps over the lazy dog -->
<!--[if IE 7]>
<link rel="stylesheet" type="text/css" href="/supersheet.css" />
<![endif]-->
<!-- Pack my box with five dozen liquor jugs -->
Сначала я попытался использовать следующее регулярное выражение для сопоставления содержимого внутри условных комментариев:
/<!--.*?stylesheet.*?-->/s
Не удалось, так как регулярное выражение соответствует всему содержимому до первого <!--
и последнее -->
, Затем я попытался использовать другой шаблон с предварительным утверждением:
/<!--(?=.*?stylesheet).*?-->/s
Это работает и соответствует именно то, что мне нужно. Тем не менее, следующее регулярное выражение также работает:
/<!--(?=.*stylesheet).*?-->/s
Последнее регулярное выражение не имеет неохотного квантификатора в предварительном утверждении. И теперь я в замешательстве. Может кто-нибудь объяснить мне, как это работает? Может быть, есть лучшее решение для этого примера?
Обновлено:
Я попытался использовать регулярные выражения с утверждением о предвкушении в другом документе, и он не смог обработать содержимое между комментариями. Итак, этот /<!--(?=.*?stylesheet).*?-->/s
(а также этот /<!--(?=.*stylesheet).*?-->/s
) не является правильным. Не используйте его и попробуйте другие предложения.
Обновлено:
Решение было найдено Джонни 5 (см. Ответ). Он предложил три варианта:
- Использование дефисированного дефиса для ограничения соответствия. Эта опция работает, только если между тегами нет дефиса. Если таблица стилей имеет URL
/style-sheet.css
, она не будет работать. - Использование escape-последовательности:
\K
, Отлично работает. Недостатками являются следующие:- Это ужасно медленно (в моем случае это было в 8-10 раз медленнее, чем другие решения)
- Доступно только с PHP 5.2.4
- Используя взгляд, чтобы сузить матч. Это цель, которую я пытался достичь, но моего опыта использования косвенных утверждений было недостаточно для выполнения задачи.
Я думаю, что следующее является хорошим решением для моего примера:
/(?s)<!--(?:(?!<!).)+?stylesheet.+?-->/
То же самое, но с s
модификатор в конце:
/<!--(?:(?!<!).)+?stylesheet.+?-->/s
Как я уже сказал, это хорошее решение, но мне удалось улучшить шаблон и нашел другое, которое в моем случае работает быстрее.
Итак, окончательное решение заключается в следующем:
/<!--(?:(?!-->).)+?stylesheet.+?-->/s
Спасибо всем участникам за интересные ответы.
2 ответа
Соответствовать только части <!--
...stylesheet
...-->
Есть много способов:
1.) Используйте дефисированный дефис [^-]
ограничить матч и остаться между <!--
а также stylesheet
(?s)<!--[^-]+stylesheet.+?-->
[^-]
разрешает только символы, которые не являются дефисами. Смотрите тест в regex101.
2.) Чтобы получить "последний" или ближайший матч без особых усилий, также можно поставить жадную точку, прежде чем ᗧ съесть. Имеет смысл, если не соответствует глобально / только один элемент для сопоставления. Используйте \K для сброса после жадности:
(?s)^.*\K<!--.+?stylesheet.+?-->
Смотрите тест в regex101. Также можно использовать группу захвата и получить $ 1:(?s)^.*(<!--.+?stylesheet.+?-->)
3.) Использование заглядывания, чтобы сузить его, обычно более затратно:
(?s)<!--(?:(?!<!).)+?stylesheet.+?-->
Смотрите тест в regex101. (?!<!).
смотрит вперед на каждого персонажа между <!--
а также stylesheet
если не начать другой <!
... чтобы остаться внутри одного элемента. Похоже на отрицание дефиса.
Вместо .*
я использовал .+
для одного или нескольких - зависит от того, что должно быть сопоставлено. Вот +
подходит лучше.
Какое решение использовать, зависит от точных требований. Для этого случая я бы использовал первый.
Строка stylesheet
упоминается только один раз в тестовом документе, поэтому оба используемых вами регулярных выражения будут совпадать, но по-разному.
<!--(?=.*?stylesheet).*?-->/s
Этот делает следующее:
- Захватить
<!--
, - Смотри вперед, захватывая персонажей вплоть до
stylesheet
, Сбой, если не найден. - Захватывайте персонажи вплоть до
-->
,
<!--(?=.*stylesheet).*?-->/s
Этот делает следующее:
- Захватить
<!--
, - Смотри вперед, захватывая любого персонажа, пока это уже невозможно. Вернуться назад, постоянно пытаясь соответствовать
stylesheet
, Сбой, если не найден. - Захватывайте персонажи вплоть до
-->
,
По сути, нужно значительно отказаться, а другой нет.
Если ваша тема вместо этого...
таблиц стилей->
вы получите два разных результата. Первый найдет первый stylesheet
в то время как последний найдет второй (и последний), так как он начинает поиск с конца строки.