Опубликован: 18.06.2007 | Доступ: свободный | Студентов: 1354 / 35 | Оценка: 4.14 / 3.29 | Длительность: 12:44:00
ISBN: 978-5-94774-604-4
Лекция 2:

Механизм работы регулярных выражений. Поиск с возвратами

< Лекция 1 || Лекция 2: 1234 || Лекция 3 >
Аннотация: Логика работы регулярных выражений и ее понимание.

2.1. Текущая позиция поиска

Процесс сопоставления заданного текста шаблону начинается с начала текста (если в шаблоне не задано другое) и с начала шаблона. Механизм поиска совпадения хранит текущие позиции в тексте и в шаблоне, до которых он обнаружил совпадение куска текста куску шаблона. Совпадение может существовать с разных позиций текста. Например, шаблон с "жадным" квантификатором

a*

может совпасть со строкой

aaab

с первой, второй и третьей буквы, но при нахождении совпадения учитывается лишь более ранняя находка, поэтому этот шаблон будет соответствовать всем трем буквам " a " с начала строки. После того, как это совпадение будет найдено, механизм поиска совпадения закончит работу. (Но в случае модификатора g работа будет продолжена, что мы увидим при рассмотрении примеров работы этого модификатора.)

Если с текущей начальной позиции в тексте совпадение не будет обнаружено, то в дело вступает механизм смещения текущей позиции поиска: состояние шаблона и позиция поиска в шаблоне будут сброшены в начальное состояние, а текущая позиция в тексте будет продвинута на один символ. После этого начнется новая итерация поиска совпадения. (Но если шаблон привязан к началу текста якорем \A или ^, то в случае неудачи второй итерации не будет, ведь в этом случае шаблон должен совпасть только в начале текста и нигде больше.) Такие итерации будут повторяться, пока начальная позиция в тексте не выйдет за конец этого текста. В этом случае поиск закончится неудачей. Поиск заканчивается удачей, когда в процессе его работы текущая позиция в шаблоне выходит за пределы шаблона.

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

2.2. Возвраты и сохраненные состояния

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

\w+bb

и строку

aaabb

При сопоставлении этой строки шаблону модификатор + захватит все символы, и на долю подшаблона bb ничего не останется. Но после этой неудачи не произойдет сразу итерации поиска со следующего символа, т.к. в совпавшей части шаблона имеются квантификаторы, у которых может быть разное число повторов. В этом случае произойдет возврат к последнему подшаблону с таким квантификатором и к позиции в тексте, с которой он совпадал. Но для таких возвратов надо для каждого пройденного подшаблона с квантификатором запоминать значения этого квантификатора и позицию в тексте, с которой совпал этот подшаблон. В нашем случае вначале для подшаблона \w+ будет запомнено 5 состояний: что он захватил с начала текста a, aa, aaa, aaab и aaabb.

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

Т.к. для литерала b в шаблоне не находится соответствия, "жадность" квантификатора будет уменьшена на один символ, и мы будем иметь совпадение подшаблона \w+ с подстрокой aaab, далее подшаблон b совпадет с символом b, а на следующий подшаблон b ничего не останется. На самом деле, литералы сравниваются не по одному символу, а по целому литералу (если не указан модификатор i ), а пример выше я привел для наглядности рассуждений.

Лишь при втором уменьшении "жадности" квантификатора + будет найдено совпадение для всего шаблона:

\w+ совпадет с aaa,

подшаблон bb совпадет с bb.

Если бы текст на этом не заканчивался, то все равно было бы зафиксировано совпадение и оператор поиска вернул бы истину. Ведь шаблон поиска не привязан к концу строки якорями $, \z или \Z. Если бы это имело место, то поиск мог бы закончиться успехом только тогда, когда шаблон и текст исчерпываются одновременно. Точнее говоря, после исчерпания шаблона, оканчивающегося на $ или \Z, в тексте может еще остаться единственный символ новой строки \n.

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

Разумеется, квантификаторы вида a{20} не могут порождать возвратов, это просто иная запись литерала.

Что будет в случае с минимальным квантификатором? В этом случае он начинает захват с наименьшего возможного значения квантификатора (от нуля и далее). А механизм поиска кроме запоминания текущей позиции совпадения для каждого такого подшаблона и его значения, конечно, "знает" о том, какой вид имеет этот квантификатор: минимальный или максимальный.

Если рассмотреть пример шаблона

\w{1,3}?b

и строку

aaaabb

то совпадение с первого символа строки вообще не будет найдено ни при каких значениях квантификатора. Оно будет найдено со второго символа строки и после того, как будут перепробованы значения квантификатора 1, 2 и 3. В результате получим совпадение подшаблона \w{1,3}? с подстрокой aaa, и затем подшаблон b совпадет с символом b. На этом поиск совпадения успешно закончится.

< Лекция 1 || Лекция 2: 1234 || Лекция 3 >
Константин Бражников
Константин Бражников
Россия
Mike .
Mike .
Россия