Разное

Регулярное выражение конец строки: Начало строки ^ и конец $

Содержание

Урок №11. Начало и конец строки | Регулярные выражения

  Обновл. 17 Ноя 2019  | 

До этого момента мы писали регулярные выражения, которые лишь частично соответствовали фрагментам данных из текста. Иногда это нежелательно, например, представьте, что нам нужно найти слово success в лог-файле. Мы ведь не хотим, чтобы наш шаблон соответствовал строке с содержимым Error: unsuccessful operation? Вот почему регулярные выражения рекомендуется писать как можно конкретнее, дабы избежать ложных срабатываний при сопоставлении с текстом.

Одним из способов ужесточения наших шаблонов является указания начала и конца строки с помощью метасимволов ^ (начало строки) и $ (конец строки). В примере выше мы можем использовать шаблон ^success, чтобы соответствовать только тем строкам, которые начинаются со слова success, а не строке Error: unsuccessful operation. И если вы будете комбинировать эти два метасимвола, то вы создадите шаблон, который будет полностью соответствовать строке в её начале и в её конце.

Обратите внимание, использование метасимвола ^ в квадратных скобках [^...] приводит к исключению определённых символов (как мы уже знаем из предыдущих уроков), а без квадратных скобок — к обозначению начала строки (как мы уже знаем из этого урока).

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

Задание №11: Начало и конец строки

Соответствовать Mission: successful
Пропустить Last Mission: unsuccessful
Пропустить Next Mission: successful upon capture of target
Решение Выражение Mission: successful будет соответствовать каждой строке, поэтому нам нужно использовать метасимволы начала и конца строки в регулярке ^Mission: successful$, чтобы соответствовать только той строке, которая начинается с Mission и заканчивается successful.

Решите задание выше, чтобы перейти к следующему уроку, либо смотрите Решение.

Оценить статью:

Загрузка…

Поделиться в социальных сетях:

Регулярные выражения, пособие для новичков. Часть 2 / Habr

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

Больше метасимволов

Есть некоторые метасимволы, которые мы еще не изучили. Большинство из них будут рассмотрены в этом разделе.

Некоторые из оставшихся метасимволов являются утверждениями нулевого размера. Они не вызывают движок для прохода по строке, они вообще не охватывают никаких символов, возможен просто успех или неудача. Например, \b это утверждение о том, что текущая позиция находится на границе (boundary) слова, при этом сам символ \b не изменяет позицию. Это означает, что утверждения нулевого размера никогда не должны повторяться, потому что, если они совпали один раз в данном месте, они, очевидно, будут соответствовать этому месту бесконечное число раз.

|

Соответствует оператору ИЛИ. Если А и В являются регулярными выражениями, то A|B будет соответствовать любая строка, которая соответствует А или В. Метасимвол | имеет очень низкий приоритет для того, чтобы заставить его работать разумно, когда вы чередуете несколько символов строки. Crow|Servo будет искать соответствие либо Crow, либо Servo, а не Cro('w' или 'S')ervo.

^

Ищет соответствие только в начале строки. Если включен флаг MULTILINE, как говорилось в прошлой части, то происходит сравнение и для каждой части после символа новой строки.

Например, если вы хотите найти только те строки, у которых в начале имеется From, то в регулярном выражении записывается ^From:

>>> print re.search(‘^From’, ‘From Here to Eternity’)
<_sre.SRE_Match object at 0x…>
>>> print re.search(‘^From’, ‘Reciting From Memory’)
None

$

То же, что ^, но в конце строки, которая определяется либо, собственно по концу строки как таковому, либо по символу новой строки.

>>> print re.search(‘}$’, ‘{block}’)
<_sre.SRE_Match object at 0x…>
>>> print re.search(‘}$’, ‘{block} ‘)
None
>>> print re.search(‘}$’, ‘{block}\n’)
<_sre.SRE_Match object at 0x…>

\A

Совпадение только в начале строки, то есть тоже, что ^, но не зависит от флага MULTILINE

\Z

Совпадение только в конце строки, то есть тоже, что $, но не зависит от флага MULTILINE

\b

Граница слова. Слово определяется как последовательность символов чисел и/или букв, так что границы слова представляют пробелы или любые символы, не относящиеся к перечисленным.

Следующий пример ищет слово class только когда это отдельное слово. Если оно содержится внутри другого слова, соответствия не находится:

>>> p = re.compile(r’\bclass\b’)
>>> print p.search(‘no class at all’)
<_sre.SRE_Match object at 0x…>
>>> print p.search(‘the declassified algorithm’)
None
>>> print p.search(‘one subclass is’)
None

Есть две тонкости, которые вы должны помнить при использовании этой специальной последовательности. Во-первых, это одно из худших столкновений между строковыми литералами Python и последовательностями регулярных выражений: в строковых литералах Python, \b это символ backspace, ASCII значение 8. Если не использовать «сырые» строки, Python будет конвертировать \b в backspace, и ваше регулярное выражение будет не таким, как задумано:

>>> p = re.compile(‘\bclass\b’)
>>> print p.search(‘no class at all’)
None
>>> print p.search(‘\b’ + ‘class’ + ‘\b’)
<_sre.SRE_Match object at 0x…>

Во-вторых, внутри класса символов нельзя использовать данное сочетание, потому как сочетание \b для совместимости со строковыми литералами Python представляет символ backspace.

\B

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

Группировка

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

From: [email protected]

User-Agent: Thunderbird 1.5.0.9 (X11/20061227)

MIME-Version: 1.0

To: [email protected]

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

Группы обозначаются метасимволами в виде круглых скобок '(', ')'. '(' и ')' имеют такой же смысл, как в математических выражениях; они группируют вместе выражения, содержащиеся в них, и вы можете повторять содержание группы повторяющими квалификаторами, такими как *, +, ? и {m, n}. Например, (ab)* будет соответствовать нулю или более повторений ab.

>>> p = re.compile(‘(ab)*’)
>>> print p.match(‘ababababab’).span()
(0, 10)

Группы, определяемые скобками, также захватывают начальные и конечные индексы совпадающего текста; это может быть получено передачей аргумента group(), start(), end() и span(). Группы нумеруются, начина с 0. Группа 0 имеется всегда, это само регулярное выражение целиком, так что методы MatchObject всегда содержат 0 как аргумент по умолчанию:

>>> p = re.compile(‘(a)b’)
>>> m = p.match(‘ab’)
>>> m.group()
‘ab’
>>> m.group(0)
‘ab’

Подгруппы нумеруются слева направо, от 1 и далее. Группы могут быть вложенными; для того чтобы определить число вложений, просто подсчитываем слева направо символы открывающей скобки:

>>> p = re.compile(‘(a(b)c)d’)
>>> m = p.match(‘abcd’)
>>> m.group(0)
‘abcd’
>>> m.group(1)
‘abc’
>>> m.group(2)
‘b’

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

>>> m.group(2,1,2)
(‘b’, ‘abc’, ‘b’)

Метод groups() возвращает кортеж строк для всех подгрупп, начиная с 1-ой:

>>> m.groups()
(‘abc’, ‘b’)

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

Например, следующее РВ обнаруживает в строке дважды подряд повторяющиеся слова:

>>> p = re.compile(r'(\b\w+)\s+\1′)
>>> p.search(‘Paris in the the spring’).group()
‘the the’

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

Группы с захватом содержимого и именованные группы

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

В Perl 5 было добавлено несколько дополнительных функций для стандартных регулярных выражений, и модуль re поддерживает большинство из них. Было бы сложно выбрать новые односимвольные метасимволы или новые последовательности с бэкслешем, для того чтобы представить новые особенности так, чтобы регулярные выражения Perl без путаницы отличались от стандартных регулярных выражений. Если выбрать в качестве нового метасимвола, например, &, то старые регулярные выражения принимали бы его как обычный символ и нельзя было бы экранировать его \& или [&].

Решение, выбранное разработчиками Perl состояло в том, чтобы использовать в качестве расширения синтаксиса (?...). Знак вопроса после скобки в случае обычного РВ это синтаксическая ошибка, поскольку ? нечего повторять, так что это не приводит к каким-либо проблемам в совместимости. Символы сразу после ? показывают какое расширение используется, так (?=foo) это одно (положительное утверждение о предпросмотре), а (?:foo) это что-то другое (группа без захвата содержимого, включающая подвыражение foo).

К расширенному синтаксису Perl в Python добавляется собственное расширение. Если первый символ после знака вопроса P, то это означает что используется расширение, специфичное для Python. В настоящее время существуют два таких расширения: (?P<some_name>... )определяет именованную группу, а (?P=some_name) служит для нее обратной ссылкой. Если в будущих версиях Perl 5 добавятся аналогичные возможности, использующие другой синтаксис, модуль re будет изменен для поддержки нового синтаксиса, сохраняя при этом для совместимости Python-синтаксис.

Иногда вам нужно использовать группу для сбора части регулярного выражения, но вы не заинтересованы в извлечении содержимого группы. Вы можете сделать это, используя группу без захвата содержимого: (?:...), где вы можете заменить ... любым другим регулярным выражением:

>>> m = re.match(«([abc])+», «abc»)
>>> m.groups()
(‘c’,)
>>> m = re.match(«(?:[abc])+», «abc»)
>>> m.groups()
()

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

Более важной особенностью являются именованные группы: вместо ссылки на них по номерам, на эти группы можно ссылаться по имени.

Синтаксис именованных групп это одно из специфичных Python-расширений: (?P<some_name>...). Именованные группы ведут себя в точности как обычные, но вдобавок к этому ассоциируются с каким-то именем. Методы MatchObject, которые использовались для обычных групп принимают как числа, ссылающиеся на номер группы, так и строки, содержащие имя необходимой группы. То есть именованные группы все также принимают и числа, так что вы можете получить информацию о группе двумя способами:

>>> p = re.compile(r'(?P<word>\b\w+\b)’)
>>> m = p.search( ‘(((( Lots of punctuation )))’ )
>>> m.group(‘word’)
‘Lots’
>>> m.group(1)
‘Lots’

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

InternalDate = re.compile(r’INTERNALDATE «‘

        r'(?P<day>[ 123][0-9])-(?P<mon>[A-Z][a-z][a-z])-‘

        r'(?P<year>[0-9][0-9][0-9][0-9])’

        r’ (?P<hour>[0-9][0-9]):(?P<min>[0-9][0-9]):(?P<sec>[0-9][0-9])’

        r’ (?P<zonen>[-+])(?P<zoneh>[0-9][0-9])(?P<zonem>[0-9][0-9])’

        r'»‘)

Синтаксис обратных ссылок в регулярном выражение типа (...)\1 ссылается на номер группы. Более естественно было бы использовать вместо номеров имена групп. Другое Python расширение: (?P=name) показывает, что содержимое названной группы снова должно быть сопоставлено в текущей позиции. Наше прежнее регулярное выражение для поиска дублирующихся слов, (\b\w+)\s+\1 может быть также записано как (?P<doble_word>\b\w+)\s+(?P=doble_word):

>>> p = re.compile(r'(?P<word>\b\w+)\s+(?P=word)’)
>>> p.search(‘Paris in the the spring’).group()
‘the the’

Опережающие проверки

Проверки доступны в позитивной и негативной (ретроспективной) форме, и выглядят так:

(?=...)

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

(?!...)

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

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

Шаблон для такого сравнения довольно прост:

.*[.].*$

Отметим, что символ . требует специальных скобок, поскольку сама точка является метасимволом, что видно в этом же выражении. Также отметим заключительный $; он добавлен для того, чтобы обеспечить включение в расширение всего остатка строки.

Теперь, рассмотрим проблему немного шире; что, если вы хотите сравнить имена всех файлов, у которых расширение не bat? Несколько неверных попыток:

.*[.][^b].*$

Первая попытка состоит в том, чтобы исключить bat требованием, чтобы первый символ расширение был не b. Это неправильно, потому что шаблон также исключит foo.bar.

.*[.]([^b]..|.[^a].|..[^t])$

Выражение получится еще неряшливее, когда вы решите подправить первое решение отдельным заданием нужных символов: первый символ расширения должен быть не b; второй — не a; третий — не t. Это позволит включить foo.bar и отклонить autoexec.bat, но требует расширения из трех букв и не будет работать с двухсимвольными расширениями имен файлов, наприме sendmail.cf. Тогда нам придется снова усложнить шаблон, чтобы решить эту проблему:

.*[.]([^b].?.?|.[^a]?.?|..?[^t]?)$

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

Шаблон теперь действительно готов, его сложно читать и понимать. Еще хуже, если изменится проблема и вам нужно будет исключить и bat, и exe расширения, шаблон станет еще более сложным и запутанным.

Негативная опережающая проверка решает все эти затруднения:

.*[.](?!bat$).*$

Отрицательный предпросмотр означает: если выражение bat не соответствует данной позиции, сравнить остаток шаблона; если обнаружено соответствие bat$, то весь шаблон нам не подходит. Заключающий выражение знак $ нужен для того, чтобы было разрешено и такое выражение, как sample.batch.

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

.*[.](?!bat$|exe$).*$

Изменение строк

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





Метод/атрибут Цель
split() Разбить строку в список там, где есть совпадение РВ
sub() Найти все подстроки совпадений с РВ и заменить их другой строкой
subn() Делает то же, что и sub(), но возвращает новую строку и число замещений
Разбиение строк

Метод шаблона split() разбивает строку на части там, где есть совпадение РВ, возвращая список частей. Это похоже на строковый метод split(), но обеспечивает всеобщность в разделителях, по которым происходит разбиение; обычный split() обеспечивает разбиение только по whitespace-символам или фиксированной строке. Как и следовало ожидать, существует и модульная функция re.split().

.split(string[, maxsplit=0])

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

В следующем примере разделителем является любая последовательность небуквенно-цифровых символов.

>>> p = re.compile(r’\W+’)
>>> p.split(‘This is a test, short and sweet, of split().’)
[‘This’, ‘is’, ‘a’, ‘test’, ‘short’, ‘and’, ‘sweet’, ‘of’, ‘split’, »]
>>> p.split(‘This is a test, short and sweet, of split().’, 3)
[‘This’, ‘is’, ‘a’, ‘test, short and sweet, of split().’]

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

>>> p = re.compile(r’\W+’)
>>> p2 = re.compile(r'(\W+)’)
>>> p.split(‘This… is a test.’)
[‘This’, ‘is’, ‘a’, ‘test’, »]
>>> p2.split(‘This… is a test.’)
[‘This’, ‘… ‘, ‘is’, ‘ ‘, ‘a’, ‘ ‘, ‘test’, ‘.’, »]

Функция модуля re.split() в качестве первого аргумента забирает РВ, а в остальном ведет себя также:

>>> re.split(‘[\W]+’, ‘Words, words, words.’)
[‘Words’, ‘words’, ‘words’, »]
>>> re.split(‘([\W]+)’, ‘Words, words, words.’)
[‘Words’, ‘, ‘, ‘words’, ‘, ‘, ‘words’, ‘.’, »]
>>> re.split(‘[\W]+’, ‘Words, words, words.’, 1)
[‘Words’, ‘words, words.’]

Поиск и замена

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

.sub(replacement, string[, count=0])

Возвращает строку, получающуюся при замене. Если шаблон не найден строка возвращается неизменной.

Добавочный аргумент count это максимальное число замещаемых совпадений.

Простой пример использования метода sub(). Названия цветов замещаются словом colour:

>>> p = re.compile( ‘(blue|white|red)’)
>>> p.sub(‘colour’, ‘blue socks and red shoes’)
‘colour socks and colour shoes’
>>> p.sub(‘colour’, ‘blue socks and red shoes’, count=1)
‘colour socks and red shoes’

Метод subn() делает то же самое, но возвращает кортеж, содержащий новую строку и число произведенных замен:

>>> p = re.compile( ‘(blue|white|red)’)
>>> p.subn( ‘colour’, ‘blue socks and red shoes’)
(‘colour socks and colour shoes’, 2)
>>> p.subn( ‘colour’, ‘no colours at all’)
(‘no colours at all’, 0)

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

>>> p = re.compile(‘x*’)
>>> p.sub(‘-‘, ‘abxd’)
‘-a-b-d-‘

Если заместителем служит строка, то в ней поддерживаются символы экранирования. Так, \n это одиночный символ новой строки, \r это возврат каретки и так далее. Обратные ссылки, такие как \6 замещаются подстрокой, совпавшей с соответствующей группой в РВ. Это позволяет вам включать части оригинального текста в результат замены строки.

Пример соответствует слову section в части строки, предшествующей части в фигурных скобках {, }, и заменяет section на subsection:

>>> p = re.compile(‘section{ ( [^}]* ) }’, re.VERBOSE)
>>> p.sub(r’subsection{\1}’,’section{First} section{second}’)
‘subsection{First} subsection{second}’

Также имеется возможность ссылаться на именованные группы. Для этого используется последовательность \g<...>, где в качестве ... может выступать номер или имя группы. \g<2> это эквивалент \2, но он не двусмыслен в таких заместителях, как \g<2>0. (\20 будет интерпретироваться как ссылка на группу 20, а не как вторую группу с последующим литералом ‘0’.) Следующие операции эквиваленты, но используют три различных способа:

>>> p = re.compile(‘section{ (?P<name> [^}]* ) }’, re.VERBOSE)
>>> p.sub(r’subsection{\1}’,’section{First}’)
‘subsection{First}’
>>> p.sub(r’subsection{\g<1>}’,’section{First}’)
‘subsection{First}’
>>> p.sub(r’subsection{\g<name>}’,’section{First}’)
‘subsection{First}’

Заместитель также может быть и функцией, дающем вам больше возможностей управления. Если это так, функция вызывается для каждого случая неперекрытия шаблона. При каждом вызове функции передается в качестве аргумента MatchObject.

В следующем примере функция замены переводит десятичные числа в шестнадцатеричные:

>>> def hexrepl( match ):

…     «Return the hex string for a decimal number»

…     value = int( match.group() )

…     return hex(value)


>>> p = re.compile(r’\d+’)
>>> p.sub(hexrepl, ‘Call 65490 for printing, 49152 for user code.’)
‘Call 0xffd2 for printing, 0xc000 for user code.’

Общие проблемы

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

Использование строковых методов

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

Представим, нужно заменить одну фиксированную строку другой, например, заменить слово word словом deed. Здесь, конечно, подойдет функция re.sub(), но рассмотрим строковый метод replace(). Отметим, что replace() будет также заменять word внутри слов, меняя swordfish на sdeedfish, но и простецкое регулярное выражение будет делать это то же. (Чтобы избежать выполнения замещения на части слов, шаблон должен содержать \bword\b).

Другая распространенная задача это удаление одиночного символа из строки или замена его другим символом. Вы можете сделать это чем-то вроде re.sub('\n', ' ', S), но метод translate() справится с обеими задачами и сделает это быстрее, чем любое регулярное выражение.

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

match() в сравнении с search()

Функция match() ищет соответствие РВ в начале строки, тогда как search() ищет соответствие во всей строке. Важно иметь в виду это различие:

>>> print re.match(‘super’, ‘superstition’).span()
(0, 5)
>>> print re.match(‘super’, ‘insuperable’)
None
>>> print re.search(‘super’, ‘superstition’).span()
(0, 5)
>>> print re.search(‘super’, ‘insuperable’).span()
(2, 7)

У вас может возникнуть соблазн всегда пользоваться re.match(), просто добавляя перед вашим регулярным выражением .*. Сопротивляйтесь этому искушению, и вместо этого используйте re.search(). Компилятор регулярных выражений производит небольшой анализ РВ для того, чтобы ускорить процесс поиска соответствия. Один из видов такого анализа заключается в определении того, что должно быть первым символом совпадения, например, совпадение с шаблоном, начинающимся с Crow, должно начинаться с 'C'. Этот анализ приводит к тому, что движок быстро пробегает строку в поиске начального символа, и начинает полное сравнение только, если найден символ ‘C’.

Добавление .* сводит на нет эту оптимизацию, требуя сканирования до конца строки, а затем возвращения, чтобы сравнить остаток регулярного выражения. Используйте вместо этого re.search().

Жадный против нежадного

При повторении в РВ, таком как a*, результирующее действие съедает настолько большую часть шаблона, насколько это возможно. На этом часто обжигаются те, кто хочет найти пару симметричных определителей, таких как угловые скобки , окружающие HTML-теги. Наивный подход к шаблону сопоставления тега HTML не будет работать из-за «жадного» характера .*:

>>> s = ‘<html><head><title>Title</title>’
>>> len(s)
32
>>> print re.match(‘<.*>’, s).span()
(0, 32)
>>> print re.match(‘<.*>’, s).group()
<html><head><title>Title</title>

РВ сопоставляет '<' в первом теге — html, и .* забирает остаток строки. В итоге сопоставление простирается от открывающей склюки '<' тега html до закрывающей скобки ‘>' закрывающего тега /title, что, конечно, не есть то, чего мы хотели.

В таком случае, решение заключается в использовании нежадных определителей *?, +?, ?? или {m,n}?, которые сопоставляют так мало текста, как это возможно. В примере выше, будет выбран первый символ ‘>’ после ‘<‘, и только, если не получится, движок будет продолжать попытки найти символ ‘>’ на следующей позиции, в зависимости от того, как длинно имя тега. Это дает нужный результат:

>>> print re.match(‘<.*?>’, s).group()
<html>

(Заметим, что парсинг HTML или XML с использованием регулярных выражений является делом болезненным. Наспех сделанный шаблон может справиться с какими-то вещами, но рушится при изменении кода страницы. А хорошо продуманный шаблон может оказаться слишком сложным для того, чтобы пытаться его модифицировать. Для таких задач лучше использовать модули HTML или XML парсеров.)

Использование re.VERBOSE

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

Для таких РВ может быть полезным указание флага VERBOSE при компиляции регулярного выражения потому что это позволяет форматировать регулярное выражение более ясным образом.

Флаг VERBOSE имеет несколько особенностей. Пробелы в РВ, которые не находятся внутри класса символов игнорируется. Это означает, что выражения, такие как dog | cat эквивалентны менее читабельным беспробельным dog|cat, но [a b] будет по-прежнему соответствовать символам 'a', 'b' или пробелу. Кроме того, вы можете также помещать внутрь РВ комментарии, длящиеся с символа # до следующей строки. Форматирование будет более аккуратным при использовании тройных кавычек:

pat = re.compile(r»»»

 \s*                 # Skip leading whitespace

 (?P<header>[^:]+)   # Header name

 \s* :               # Whitespace, and a colon

 (?P<value>.*?)      # The header’s value — *? used to

                     # lose the following trailing whitespace

 \s*$                # Trailing whitespace to end-of-line

«»», re.VERBOSE)

Это гораздо проще читается, чем:

pat = re.compile(r»\s*(?P<header>[^:]+)\s*:(?P<value>.*?)\s*$»)

В заключение

Документация модуля re
Хабраблог «Регулярные выражения»
Regexp editor

Шпаргалка по регулярным выражениям — Exlab


Шпаргалка представляет собой общее руководство по шаблонам регулярных выражений без учета специфики какого-либо языка. Она представлена в виде таблицы, помещающейся на одном печатном листе формата A4. Создана под лицензией Creative Commons на базе шпаргалки, автором которой является Dave Child (подробнее).


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


Якоря

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

^[0-9]+

Здесь символ ^ обозначает начало строки. Без него шаблон соответствовал бы любой строке, содержащей цифру.


Символьные классы

Символьные классы в регулярных выражениях соответствуют сразу некоторому набору символов. Например, \d соответствует любой цифре от 0 до 9 включительно, \w соответствует буквам и цифрам, а \W — всем символам, кроме букв и цифр. Шаблон, идентифицирующий буквы, цифры и пробел, выглядит так:

\w\s


POSIX

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


Утверждения

Поначалу практически у всех возникают трудности с пониманием утверждений, однако познакомившись с ними ближе, вы будете использовать их довольно часто. Утверждения предоставляют способ сказать: «я хочу найти в этом документе каждое слово, включающее букву “q”, за которой не следует “werty”».

[^\s]*q(?!werty)[^\s]*

Приведенный выше код начинается с поиска любых символов, кроме пробела ([^\s]*), за которыми следует q. Затем парсер достигает «смотрящего вперед» утверждения. Это автоматически делает предшествующий элемент (символ, группу или символьный класс) условным — он будет соответствовать шаблону, только если утверждение верно. В нашем случае, утверждение является отрицательным (?!), т. е. оно будет верным, если то, что в нем ищется, не будет найдено.

Итак, парсер проверяет несколько следующих символов по предложенному шаблону (werty). Если они найдены, то утверждение ложно, а значит символ q будет «проигнорирован», т. е. не будет соответствовать шаблону. Если же werty не найдено, то утверждение верно, и с q все в порядке. Затем продолжается поиск любых символов, кроме пробела ([^\s]*).


Образцы шаблонов

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


Кванторы

Кванторы позволяют определить часть шаблона, которая должна повторяться несколько раз подряд. Например, если вы хотите выяснить, содержит ли документ строку из от 10 до 20 (включительно) букв «a», то можно использовать этот шаблон:

a{10,20}

По умолчанию кванторы — «жадные». Поэтому квантор +, означающий «один или больше раз», будет соответствовать максимально возможному значению. Иногда это вызывает проблемы, и тогда вы можете сказать квантору перестать быть жадным (стать «ленивым»), используя специальный модификатор. Посмотрите на этот код:

".*"

Этот шаблон соответствует тексту, заключенному в двойные кавычки. Однако, ваша исходная строка может быть вроде этой:

<a href="helloworld.htm" title="Привет, Мир">Привет, Мир</a>

Приведенный выше шаблон найдет в этой строке вот такую подстроку:

"helloworld.htm" title="Привет, Мир"

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

".*?"

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

"helloworld.htm"
"Привет, Мир"


Специальные символы

Регулярные выражения используют некоторые символы для обозначения различных частей шаблона. Однако, возникает проблема, если вам нужно найти один из таких символов в строке, как обычный символ. Точка, к примеру, в регулярном выражении обозначает «любой символ, кроме переноса строки». Если вам нужно найти точку в строке, вы не можете просто использовать «.» в качестве шаблона — это приведет к нахождению практически всего. Итак, вам необходимо сообщить парсеру, что эта точка должна считаться обычной точкой, а не «любым символом». Это делается с помощью знака экранирования.

Знак экранирования, предшествующий символу вроде точки, заставляет парсер игнорировать его функцию и считать обычным символом. Есть несколько символов, требующих такого экранирования в большинстве шаблонов и языков. Вы можете найти их в правом нижнем углу шпаргалки («Мета-символы»).

Шаблон для нахождения точки таков:

\.

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


Подстановка строк

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


Группы и диапазоны

Группы и диапазоны очень-очень полезны. Вероятно, проще будет начать с диапазонов. Они позволяют указать набор подходящих символов. Например, чтобы проверить, содержит ли строка шестнадцатеричные цифры (от 0 до 9 и от A до F), следует использовать такой диапазон:

[A-Fa-f0-9]

Чтобы проверить обратное, используйте отрицательный диапазон, который в нашем случае подходит под любой символ, кроме цифр от 0 до 9 и букв от A до F:

[^A-Fa-f0-9]

Группы наиболее часто применяются, когда в шаблоне необходимо условие «или»; когда нужно сослаться на часть шаблона из другой его части; а также при подстановке строк.

Использовать «или» очень просто: следующий шаблон ищет «ab» или «bc»:

(ab|bc)

Если в регулярном выражении необходимо сослаться на какую-то из предшествующих групп, следует использовать \n, где вместо n подставить номер нужной группы. Вам может понадобиться шаблон, соответствующий буквам «aaa» или «bbb», за которыми следует число, а затем те же три буквы. Такой шаблон реализуется с помощью групп:

(aaa|bbb)[0-9]+\1

Первая часть шаблона ищет «aaa» или «bbb», объединяя найденные буквы в группу. За этим следует поиск одной или более цифр ([0-9]+), и наконец \1. Последняя часть шаблона ссылается на первую группу и ищет то же самое. Она ищет совпадение с текстом, уже найденным первой частью шаблона, а не соответствующее ему. Таким образом, «aaa123bbb» не будет удовлетворять вышеприведенному шаблону, так как \1 будет искать «aaa» после числа.

Одним из наиболее полезных инструментов в регулярных выражениях является подстановка строк. При замене текста можно сослаться на найденную группу, используя $n. Скажем, вы хотите выделить в тексте все слова «wish» жирным начертанием. Для этого вам следует использовать функцию замены по регулярному выражению, которая может выглядеть так:

replace(pattern, replacement, subject)

Первым параметром будет примерно такой шаблон (возможно вам понадобятся несколько дополнительных символов для этой конкретной функции):

([^A-Za-z0-9])(wish)([^A-Za-z0-9])

Он найдет любые вхождения слова «wish» вместе с предыдущим и следующим символами, если только это не буквы или цифры. Тогда ваша подстановка может быть такой:

$1<b>$2</b>$3

Ею будет заменена вся найденная по шаблону строка. Мы начинаем замену с первого найденного символа (который не буква и не цифра), отмечая его $1. Без этого мы бы просто удалили этот символ из текста. То же касается конца подстановки ($3). В середину мы добавили HTML тег для жирного начертания (разумеется, вместо него вы можете использовать CSS или <strong>), выделив им вторую группу, найденную по шаблону ($2).


Модификаторы шаблонов

Модификаторы шаблонов используются в нескольких языках, в частности, в Perl. Они позволяют изменить работу парсера. Например, модификатор i заставляет парсер игнорировать регистры.

Регулярные выражения в Perl обрамляются одним и тем же символом в начале и в конце. Это может быть любой символ (чаще используется «/»), и выглядит все таким образом:

/pattern/

Модификаторы добавляются в конец этой строки, вот так:

/pattern/i


Мета-символы

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

\(


Рекомендуем также:

Синтаксис регулярных выражений

Вступление

Регулярное выражение — это шаблон, с которым сравнивается указанная строка слева направо. Большинство символов в шаблоне являются самими собой, и совпадают с соответствующими символами в искомой строке. PCRE— регулярные выражения совместимых с Perl (Perl compatible regular expressions — PCRE).

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

Метасимволы


\ общий экранирующий символ, допускающий несколько вариантов применения
^ декларирует начало данных (или строки в многострочном режиме)
$ декларирует конец данных или до завершения строки (или окончание строки в многострочном режиме)
. соответствует любому символу, кроме перевода строки (по умолчанию)
[ начало описания символьного класса
] конец описания символьного класса
| начало ветки альтерннативного выбора
( начало подмаски
) конец подмаски
? расширяет смысл метасимвола (, является также квантификатором, означающим 0 или 1 вхождение, также преобразует жадные квантификаторы в ленивые)
* квантификатор, означающий 0 или более вхождений
+ квантификатор, означающий 1 или более вхождений
{ начало количественного квантификатора
} конец количественного квантификатора

Символьные классы


Открывающая квадратная скобка объявляет начало символьного класса, завершаемого закрывающей квадратной скобкой.
Символ ] не имеет специального значения, и в случае, если закрывающая квадратная скобка необходима как член символьного класса, она должна быть первым символом непосредственно после открывающей квадратной скобки (если используется метасимвол ^, то непосредственно после него), либо экранироваться при помощи обратного слеша.

Символьный класс соответствует одиночному символу обрабатываемой строки, причем сам символ должен содержаться в наборе, определяемым классом. В случае, если первым символом описания класса является ^логика работы инвертируется: класс соответствует одиночному символу, который не содержится в наборе, определяемым классом. Если символ ^необходим как член класса, его не следует помещать первым символом в описании класса либо необходимо экранировать при помощи обратного слеша.

. Точка — любой символ
[
]
квадратные скобки — класс символов («любое из»)
[^
]
негативный класс символов («любое кроме»)
- тире — обозначение последовательности в классе символов («[0-9]» — цифры)
alnum буквы и цифры
alpha буквы
ascii символы с кодами 0 — 127
blank только пробел или символ табуляции
cntrl управляющие символы
digit десятичные цифры (то же самое, что и \d)
graph печатные символы, исключая пробел
lower строчные буквы
print печатные символы, включая пробел
punct печатные символы, исключая буквы и цифры
space пробельные символы(почти то же самое, что и \s)
upper прописные буквы
word символы «слова» (то же самое, что и \w)
xdigit шестнадцатеричные цифры

Класс пробельных символов space— это горизонтальная табуляция, перевод строки, вертикальная табуляция, разрыв страницы, возврат каретки и пробел. Учтите, что этот список включает вертикальную табуляцию. Это отличает spaceот \s, который не включает этот символ, для совместимости с Perl.

Название word— это расширение Perl, а blank— расширение GNU, начиная с версии Perl 5.8. Другое расширение Perl — это отрицание, которое указывается символом ^после двоеточия. Например, [12[:^digit:]]совпадет с «1», «2», или с любой не-цифрой.

Квантификатор

* Соответствие возникнет, если предыдущий символ будет повторяться любое число раз (в том числе и 0раз).
+ Соответствие возникнет, если предыдущий символ будет повторяться хотя бы один раз. То есть отличие от квантификатора *, здесь требуется, чтобы предшествующий символ был бы хотя бы один раз.
? Соответствие возникнет, если предыдущего символа вообще не было, либо он был только один раз.
{n} Соответствие возникнет, если предыдущий символ будет повторяться ровно nраз.
{n,} Соответствие возникнет, если предыдущий символ будет повторяться nили более раз.
{n,m} Соответствие возникнет, если предыдущий символ будет повторяться от nдо mраз.

Якоря

^ привязка к началу строки
$ привязка к концу строки

По умолчанию, вне символьного класса метасимвол начала строки ^соответствует началу обрабатываемых данных (если не используются модификаторы). Внутри символьного класса он ^имеет совершенно другое значение.

Метасимвол начала строки ^не обязан быть первым символом шаблона в случае, если в шаблоне используются несколько альтернатив, но должен быть первым символом в каждой из альтернатив, в которой он встречается, если шаблон когда-либо сопоставим с соответствующей веткой. Если все альтернативы начинаются с метасимвола начала строки ^, то шаблон ограничен для совпадения исключительно в начале строки, говорят что шаблон «заякорен». (Существуют и другие способы «заякорить» шаблон).

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

Альтернативный выбор

Символ вертикальной черты |используется для разделения альтернативных масок. Например, шаблон яблоко|грушасоответствует как «яблоко», так и «груша». Допустимо указывать любое количество альтернатив, также допустимо указывать пустые альтернативы (соответствуют пустой строке). В процессе поиска соответствия просматриваются все перечисленные альтернативы слева направо, останавливаясь после первого найденного соответствия. В случае, если альтернативные варианты перечислены в подмаске, то весь шаблон совпадет только в случае соответствия одного из альтернативных вариантов подмаски и остатка основного шаблона.

Условные подмаски

В PCRE реализована возможность подчинять шаблон условию либо выбирать из двух условных подмасок в зависимости от успеха сопоставления предыдущей подмаски. Условные подмаски имеют две допустимые формы использования:

(?(condition)yes-pattern) В случае выполения условия condition, используется подмаска yes-pattern
(?(condition)yes-pattern|no-pattern) В случае выполения условия condition, используется подмаска yes-pattern, в противном случае no-pattern

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

( \( )? [^()]+ (?(1) \) )

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

Следующая часть соответствует одному или более символам, отличным от круглой скобки.

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

Если условием является строка (R), оно будет выполнено, если будет произведен рекурсивный вызов к шаблону или подмаске. На «самом верхнем уровне» условие ложно.

Если условие не является последовательностью цифр или (R), оно должно быть утверждением. Это может быть либо положительная или отрицательная проверка последующего либо предыдущего текста. Рассмотрим данный шаблон, снова содержащий незначащие пробелы, с двумя альтернативами на второй строке:

(?(?=[^a-z]*[a-z])

\d{2}-[a-z]{3}-\d{2} | \d{2}-\d{2}-\d{2} )

Приведен пример с утверждающим условием касательно предшествующего текста, которое выполняется для необязательной последовательности не-букв с последующей буквой. Говоря другими словами, указанное условие проверяет наличие хотя бы одной предшествующей буквы. В случае, если буква найдена, выполняется сопоставление с первой альтернативой, в противном случае — со второй альтернативой. Приведенный шаблон соответствует строкам двух видов: dd-aaa-dd либо dd-dd-dd, где aaaa — это буквы, а dd — цифры.

Комментарии

Служебная последовательность (?#обозначает начало комментария, который продолжается до ближайшей закрывающей скобки. Вложенные скобки не допускаются. Символы, находящиеся внутри комментария, не принимают участия в сопоставлении шаблона.

PHP функции по работе с регулярными выражениями

  • preg_grep — Возвращает массив вхождений, которые соответствуют шаблону
  • preg_match — Выполняет проверку на соответствие регулярному выражению
  • preg_match_all — Выполняет глобальный поиск шаблона в строке
  • preg_replace — Выполняет поиск и замену по регулярному выражению
  • preg_replace_callback — Выполняет поиск по регулярному выражению и замену
  • preg_split — Разбивает строку по регулярному выражению
  • preg_quote — Экранирует символы в регулярных выражениях
  1. Регулярные выражения
  2. Примеры
  3. RegExp

. См. Ниже внутренний вид механизма регулярных выражений.

Аналогично, $ соответствует сразу после последнего символа в строке. c $ соответствует c в abc, а $ не соответствует вообще.

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

Полезные приложения

При использовании регулярных выражений в языке программирования для проверки пользовательского ввода очень важно использовать якоря.затем может соответствовать в начале строки (перед f в приведенной выше строке), а также после каждого разрыва строки (между \ n и s). Точно так же $ по-прежнему соответствует концу строки (после последнего e), а также перед каждым разрывом строки (между e и \ n).

В текстовых редакторах, таких как EditPad Pro или GNU Emacs, и инструментах регулярных выражений, таких как PowerGREP, каретка и доллар всегда совпадают в начале и конце каждой строки. Это имеет смысл, потому что эти приложения предназначены для работы с файлами целиком, а не с короткими строками.В Ruby и std :: regex каретка и доллар также всегда совпадают в начале и конце каждой строки. В Boost они по умолчанию совпадают в начале и конце каждой строки. Boost позволяет отключить это с помощью regex_constants :: no_mod_m при использовании грамматики ECMAScript.

Во всех других языках программирования и библиотеках, обсуждаемых на этом веб-сайте, вы должны явно активировать эту расширенную функциональность. Его традиционно называют «многострочным режимом». В Perl вы делаете это, добавляя m после кода регулярного выражения, например: m / ^ regex $ / m ;.В .NET привязки совпадают до и после символов новой строки, когда вы указываете RegexOptions.Multiline, например, в Regex.Match («строка», «регулярное выражение», RegexOptions.Multiline).

Символы разрыва строки

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

Постоянные привязки начала и конца строки

\ A всегда соответствует только началу строки. Точно так же \ Z всегда соответствует только концу строки. Эти два токена никогда не совпадают при переносе строки. Это верно для всех разновидностей регулярных выражений, обсуждаемых в этом руководстве, даже когда вы включаете «многострочный режим». В EditPad Pro и PowerGREP, где курсор и доллар всегда совпадают в начале и конце строк, \ A и \ Z совпадают только в начале и в конце всего файла.

JavaScript, POSIX, XML и XPath не поддерживают \ A и \ Z. Вы привыкли использовать для этой цели курсор и доллар.

Расширения GNU для регулярных выражений POSIX используют \ ‘(обратная кавычка) для соответствия началу строки и \ ‘(одинарная кавычка) для соответствия концу строки.

Строки, заканчивающиеся разрывом строки

Поскольку Perl возвращает строку с новой строкой в ​​конце при чтении строки из файла, механизм регулярных выражений Perl сопоставляет $ в позиции перед разрывом строки в конце строки, даже если -строчный режим выключен.\ d + $ соответствует 123 независимо от того, является ли строка темы 123 или 123 \ n.

Большинство современных разновидностей регулярных выражений скопировали это поведение. Сюда входят .NET, Java, PCRE, Delphi, PHP и Python. Это поведение не зависит от каких-либо настроек, таких как «многострочный режим».

Во всех этих вариантах, кроме Python, \ Z также соответствует перед окончательным разрывом строки. Если вам нужно совпадение только в самом конце строки, используйте \ z (z в нижнем регистре вместо Z в верхнем регистре). \ A \ d + \ z не соответствует 123 \ n. \ z соответствует после разрыва строки, что не соответствует классу сокращенных символов.

В Python \ Z соответствует только самому концу строки. Python не поддерживает \ z.

Строки, заканчивающиеся несколькими разрывами строки

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

Boost — единственное исключение. В Boost \ Z может соответствовать перед любым количеством разрывов конечной строки, а также в самом конце строки.может соответствовать позиции перед 4, потому что ему предшествует символ новой строки. Опять же, механизм регулярных выражений переходит к следующему токену регулярного выражения, 4, но не продвигает позицию символа в строке. 4 соответствует 4, и движок продвигает как токен регулярного выражения, так и строковый символ. Теперь движок пытается сопоставить $ в позиции до (на самом деле: до) 8. Доллар не может соответствовать здесь, потому что за этой позицией следует символ, а этот символ не является новой строкой.

И снова движок должен снова попытаться сопоставить первый токен.Ранее он был успешно сопоставлен со вторым 4-м символом, поэтому механизм продолжит работу со следующего символа, 8, где курсор не соответствует. То же самое с 6 и новой строкой.

Наконец, механизм регулярных выражений пытается сопоставить первый токен с третьим 4 в строке. Успешно. После этого движок успешно сопоставляет 4 с 4. Текущий токен регулярного выражения продвигается до $, а текущий символ продвигается до самой последней позиции в строке: пустоты после строки. Здесь не может совпадать токен регулярного выражения, которому нужен соответствующий символ.Даже не отрицательный класс символов. Однако мы пытаемся сопоставить знак доллара, а могучий доллар — странный зверь. Он имеет нулевую длину, поэтому пытается сопоставить позицию перед текущим символом. Не имеет значения, что этот «символ» является пустым после строки. Фактически доллар проверяет текущий символ. Это должно быть либо символ новой строки, либо пустое место после строки, чтобы $ соответствовала позиции перед текущим символом. Поскольку это так после примера, доллар соответствует успешно.

Поскольку $ был последним токеном в регулярном выражении, механизм обнаружил успешное совпадение: последние 4 в строке.

Сделайте пожертвование

Этот веб-сайт только что сэкономил вам поездку в книжный магазин? Сделайте пожертвование на поддержку этого сайта, и вы получите доступ без рекламы на к этому сайту!

.

linux — как использовать конец строки регулярного выражения в Windows?

Переполнение стека

  1. Около
  2. Продукты

  3. Для команд
  1. Переполнение стека
    Общественные вопросы и ответы

  2. Переполнение стека для команд
    Где разработчики и технологи делятся частными знаниями с коллегами

  3. Вакансии
    Программирование и связанные с ним технические возможности карьерного роста

  4. Талант
    Нанимайте технических специалистов и создавайте свой бренд работодателя

  5. Реклама
    Обратитесь к разработчикам и технологам со всего мира

  6. О компании

Загрузка…

    .

    java — поиск текста до конца строки регулярное выражение

    Переполнение стека

    1. Около
    2. Продукты

    3. Для команд
    1. Переполнение стека
      Общественные вопросы и ответы

    2. Переполнение стека для команд
      Где разработчики и технологи делятся частными знаниями с коллегами

    3. Вакансии
      Программирование и связанные с ним технические возможности карьерного роста

    4. Талант
      Нанимайте технических специалистов и создавайте свой бренд работодателя

    5. Реклама
      Обратитесь к разработчикам и технологам со всего мира

    6. О компании

    Загрузка…

    .Регулярное выражение

    — выберите цифры в конце строки

    Переполнение стека

    1. Около
    2. Продукты

    3. Для команд
    1. Переполнение стека
      Общественные вопросы и ответы

    2. Переполнение стека для команд
      Где разработчики и технологи делятся частными знаниями с коллегами

    3. Вакансии
      Программирование и связанные с ним технические возможности карьерного роста

    4. Талант
      Нанимайте технических специалистов и создавайте свой бренд работодателя

    5. Реклама
      Обратитесь к разработчикам и технологам со всего мира

    6. О компании

    Загрузка…

    .

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

2021 © Все права защищены. Карта сайта