Изучаем регулярные выражения самостоятельно — Разница между жадного и ленивого квантификатора ( часть 7 )

Жадные и ленивые квантификаторы

В одной из предыдущих статей, а именно в третьей части, мы познакомились с квантификаторами повторений.

И как мы уже знаем, в регулярные выражения, существуют несколько квантификаторов повторений: *, +,?, {n}, {n, }, {n, m}. С помощью них мы указываем количество повторений какого-то символа или группы символов, которые написаны перед квантификатором.

Теперь, настало время узнать, что такое жадность квантификаторов.

Жадные квантификаторы

Жадность в большинство случаев это плохо, потому что из-за этой жадности мы не получаем желаемый результат.

Например, нам нужно поискать в тексте все важные слова, которые заключены в BB коде [b]слово[/b].

К счастью, в JavaScript есть метод match() который как раз и ищет эти совпадения по указанному регулярному выражению и возвращает массив с найденными совпадениями.

Вот код самого примера:

    "use strict"

    //Строка в которой будем искать слова, заключенные в BB коде.
    var str = "Many trees were [b]blown down[/b] yesterday and the car was [b]burnt down[/b]. These children were very noisy.";

    //Регулярное выражение(шаблон), по котором будем искать слова в строке
    var reg = /\[b].+\[\/b]/g;

    //Получение и вывод массива с результатами.
    alert(str.match(reg));

Обращаем внимание на регулярное выражение. В справочнике по регулярным выражениям есть раздел “ Метасимволы “, которые экранируются. Так вот открывающая квадратная скобка тоже входит в этот список метасимволов, поэтому мы её и экранировали с помощью символа обратного слеша. Также мы экранировали слеш внутри закрывающего кода [/b].

Буква “ g “ в конце регулярного выражения, это модификатор шаблона. И оно указывает на то, чтобы поиск был глобальным. То есть, чтобы искать все совпадения, во всей строке. Без этого модификатора, поиск остановится на первое найденное совпадение.

Ну и как мы уже знаем ".+" означает повторение любого символа, от одного до бесконечности.

Если мы посмотрим на содержимое полученного массива, то мы увидим только одно большое совпадение.

жадность квантификаторов повторений

Но, это не то что мы хотели. Мы хотим, чтобы каждое слово, заключённое в BB коде, считалось как отдельное совпадение. То есть мы должны получить массив, который содержит только слова [b]blown down[/b] и [b]burnt down[/b].

Вот здесь и заключается проблема жадности квантификаторов повторений.

Давайте разберёмся, как работает написанное нами регулярное выражение и почему мы не получили желаемый результат?

Как мы знаем, каждому символу из регулярного выражения соответствует определённый символ из строки.

Анализируем подробно каждый шаг поиска совпадений в строке, по указанному регулярному выражению.

    var reg = /\[b].+\[\/b]/g;

1. Значит первого символа которого мы будем искать в строке, это открывающая квадратная скобка "[", затем букву "b", затем закрывающею квадратную скобку "]".

поиск открывающего BB кода в строке

2. Дальше, в регулярном выражении находится точка. Как мы знаем точка это любой символ. Смотрим, буква "b" соответствует точки? Да соответствует. И так как после точки у нас стоит квантификатор повторений "+", то мы последовательно проверяем каждого символа.

Буква "l" соответствует точки? Да соответствует. Буква "o" соответствует точки? Да соответствует. И так далее.

Доходим до открывающей квадратной скобки, смотрим квадратная скобка соответствует точки? Да соответствует. Слеш соответствует, да соответствует. И как мы понимаем все символы до конца строки, будут соответствовать нашей точки.

Поиск любого символа в строке

Поиск дошёл до конца строки, но в регулярном выражении остались ещё символы, которые нужно проверить для полного соответствия.

После ".+" следующим символом для проверки это открывающая квадратная скобка. Но, здесь встаёт вопрос, где искать в строке эту открывающею квадратную скобку, ведь поиск дошёл уже до конца строки?

В этом случае, движок проверки на соответствие, понимает, что возможно он взял слишком много совпадений по шаблону ".+", и для того чтобы найти эту открывающею скобку в строке, он переходит в фазу возврата.

То есть, поиск идёт обратно, с право на лево, начиная с конца строки. Таким образом проверяет каждый символ, на соответствие открывающей квадратной скобки.

Смотрим, точка в конец строки соответствует квадратной скобки? Нет, не соответствует. Идём дальше. Буква "y" соответствует квадратной скобки? Нет не соответствует. Продолжаем поиск. Буква "s" соответствует? Нет. Буква "i" соответствует? Нет.

И так идёт обратный поиск, до того момента, когда в строке найдётся эта открывающая квадратная скобка.

После того как он её нашёл, поиск выходит из этой фазы возврата и идёт уже с лево на право. Проверяем слеш из регулярного выражения соответствует слешу из строки? Да соответствует. Буква "b" соответствует? Да соответствует. Закрывающая квадратная скобка соответствует? Да соответствует. И так как мы проверили все символы из регулярного выражения движок завершает поиск.

Поиск совпадений — фаза возврата

И, в результате мы получаем только одно большое совпадение:

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

По умолчанию, квантификаторы повторений ".+", ".*", ".?" имеют так называемую жадность и они захватывают максимальное количество возможных совпадений.

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

Ленивые квантификаторы

Ленивый режим состоит в том, что, сразу после квантификатора повторений, ставится символ знака вопроса "?".

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

То есть, символу, который находится сразу после ленивого квантификатора ".+?" или ".*?" или же "??".

Обратите внимание, что сам знак вопроса "?" является квантификатором повторений и означает ноль или одно повторение. Но, если он указан после какого-то квантификатора, то он обретает уже другую роль. А именно делает этого квантификатора ленивым. Этот трюк действует и в случае, когда он написан после самого себя.

Теперь, давайте ещё раз попробуем поискать совпадения в указанной строке, но уже с ленивым квантификатором повторений.

Регулярное выражение у нас выглядит уже так:

    var reg = /\[b].+?\[\/b]/g;

1. Значит поиск у нас также начинается с открывающей квадратной скобкой, потом ищем букву «b» и следующим символом для поиска, также осталась квадратная закрывающая скобка.

Поиск в ленивом режиме

2. Дальше, в регулярном выражении, у нас идёт точка и как мы уже знаем, точки соответствует любой символ. Видим, что, у нас в строке после квадратных скобок "[b]" идёт буква "b". Проверяем, соответствует буква "b" нашей точки? Да соответствует. Хорошо.

В регулярном выражении после точки, у нас находится ленивый квантификатор повторений "+?", таким образом мы указываем условие увеличения количеств повторений.

Это условие состоит в том, что количество повторений может увеличиваться только в случае если текущий проверяемый символ из строки, не соответствует следующему символу из регулярного выражения. Иначе, если он соответствует, то квантификатор повторений завершает своё действие.

Текущий проверяемый символ, это буква "b". Следующем символом в регулярном выражении, который идёт после ленивого квантификатора "+?" является открывающая квадратная скобка "\[" .

Проверяем, буква "b" соответствует открывающей скобки? Нет, не соответствует. Значит увеличиваем на единичку количество повторений и переходим к следующему символу из строки.

Следующий символ у нас буква "l". Опять проверяем. Эта буква соответствует открывающей скобки? Нет, не соответствует. Значит, увеличиваем количество повторений ещё на единичку и идём дальше.

Буква "o" соответствует открывающей скобки? Нет, не соответствует. Идём дальше.

И так проверяется каждый следующий символ, пока в строке не будет найдена открывающая квадратная скобка, которая и соответствует следующему символу после ленивого квантификатора, то есть открывающей скобки из регулярного выражения.

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

Казалось бы, что здесь завершается наш поиск, но это не так, потому что, после регулярного выражения указан модификатор шаблона "g", который означает что поиск должен быть произведён глобально, то есть по всей строке.

Значит, начиная с буквы "y" из слова "yesterday" мы продолжаем поиск совпадений по указанному регулярному выражению.

Поиск совпадений в строке

И как мы видим мы нашли ещё одно совпадение.

Напоминаю что, код, самого примера изменился лишь добавлением знака вопроса после квантификатора повторений "+", в регулярном выражении.

Теперь, если мы запустим заново наш пример, то увидим уже желаемый результат:

Результат работы функции match

На этом всё дорогие читатели. Теперь мы уже знаем, как работают жадные и ленивые квантификаторы.

Как Вы заметили, при использовании жадного квантификатора получили один результат, а при использовании ленивого квантификатора совсем другой результат. Поэтому разница между ними очень существенная. Имейте это в ввиду. Желаю всем добра и успехов!

Задачи

  • 1. С помощи функции str.match(reg), вынесите в массив, курсивные слова, то есть которые находятся между тегами <em></em>. Из этого текста:

    " What do you want to have in our <em>new bedroom</em> ? We must have <em>one double bed</em> or <em>two single beds</em>."

  • 1.1 Выведите на экран полученный массив.

Понравилась статья?

Тогда поделитесь ею с друзьями и подпишитесь на новые интересные статьи.

Поделиться с друзьями:

Подписаться на новые статьи:

Delivered by FeedBurner

Поддержите пожалуйста мой проект!

<< Предыдущая статьяСледующая статья >>

Если у Вас есть какие-то вопросы или предложения, то можете писать их в комментариях или мне на почту sergiu920@mail.ru. И если Вы заметили какую-то ошибку в статье, то прошу Вас, сообщите мне об этом, и в ближайшее время я всё исправлю.

Добавляйтесь ко мне в друзья в:

Добавляйтесь в мои группы:

Подпишитесь на мои каналы:

Автор статьи: Мунтян Сергей

Копирование материалов с сайта sozdatisite.ru ЗАПРЕЩЕНО!!!

Дата добавления: 2017-03-13 04:34:18