Выбор между поглощающим и непоглощающим сравнением

Задача
Необходим шаблон для выделения наименьшей из возможных строк, а не наибольшей.

Решение
Добавьте символ ? после квантификатора, чтобы модифицировать конкретную часть шаблона:

// найти все части, выделенные полужирным шрифтом
preg_match_all('#.+?#', $html, $matches);

Или укажите в конце шаблона модификатор U, чтобы превратить все поглощающие квантификаторы в непоглощающие:

// найти все части, выделенные полужирным шрифтом
preg_match_all('#.+#U', $html, $matches);

Обсуждение
По умолчанию все регулярные выражения в PHP представляют собой так называемые поглощающие регулярные выражения. Это означает, что квантификатор всегда пытается найти совпадение с максимально возможным количеством символов. Например, возьмем шаблон p.*, означающий p, а затем 0 или более символов, и применим его к строке php. Поглощающее регулярное выражение найдет одно совпадение, поскольку после захвата начального символа p оно продолжит работу и выделит также символы hp. С другой стороны, непоглощающее регулярное выражение найдет пару совпадений. Как и раньше, оно выделит символ p и символ h, но затем, вместо того чтобы продлить свое действие, оно прервется и оставит завершающий символ p непоглощенным.


Следующая, вторая проверка
выбирает последнюю букву.

Следующий фрагмент программы показывает, как поглощающее сравнение приводит только к одному успешному результату, а непоглощающее сравнение находит два совпадения:

print preg_match_all('/p.*/', "php", $match); // поглощающее
print preg_match_all('/p.*?/', "php", $match); // непоглощающее
print preg_match_all('/p.*/U', "php", $match); // непоглощающее
1
2
2

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

Изначально все регулярные выражения были строго поглощающими. Поэтому нельзя использовать этот синтаксис с функциями ereg() или ereg_replace(). Поглощающее сравнение не поддерживается более старыми версиями механизма реализации функций регулярных выражений; вместо этого нужно использовать функции диалекта Perl.Непоглощающее сравнение часто оказывается полезным при попытке выполнения упрощенного анализа HTML-документов.


Предположим, что требуется найти весь текст между тегами полужирного шрифта.

В случае применения поглощающего сравнения это будет выглядеть так:

$html = 'I am bold. I am italic. I am also bold.';
preg_match_all('#(.+)#', $html, $bolds);
print_r($bolds[1]);
Array
(
[0] => I am bold. I am italic. I am also bold.
)

Поскольку здесь есть второй набор тегов полужирного шрифта, шаблон продлит свое действие за пределы первого тега
, что сделает невозможным корректный анализ HTML. В случае же минимальной проверки оба набора тегов будут найдены по шаблону и замкнуты:

$html = 'I am bold. I am italic. I am also bold.';
preg_match_all('#(.+?)#', $html, $bolds);
print_r($bolds[1]);
Array
(
[0] => I am bold.
[1] => I am also bold.
)

Конечно, из этого может ничего не получиться, если разметка не на 100% формально корректна и в ней присутствуют случайные теги полужирного шрифта.1 Если единственной вашей целью является удаление всех (или некоторых) тегов HTML из блока текста, то лучше вооб-
ще обойтись без регулярных выражений.


Вместо этого обратитесь
к функции strip_tags(), – она работает быстрее и корректнее. Допол-
нительную информацию можно найти в рецепте 11.11.
Заметим в заключение, что хотя идея непоглощающего сравнения
пришла из языка Perl, сам модификатор -U не совместим с Perl и уни-
кален именно для реализации Perl-диалекта регулярных выражений
в PHP. Он инвертирует все квантификаторы, превращая их из погло-
щающих в непоглощающие, а также меняет направление их действия
на обратное. Поэтому, чтобы применить поглощающий квантифика-
тор внутри шаблона, находящегося в области действия завершающего
модификатора /U, просто добавьте в конце квантификатора символ ?
точно так же, как это обычно делается для превращения квантифика-
тора из поглощающего в непоглощающий.

Оцените статью: (0 голосов)
0 5 0

Статьи из раздела PHP на эту тему:
Нахождение n-го совпадения
Переход от ereg к preg
Поиск в файле всех строк, соответствующих шаблону
Поиск слов
Проверка правильности адресов электронной почты

Вернуться в раздел: PHP / 13. Регулярные выражения