Жадность регулярные выражения python

Понять регулярные выражения в Python

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

В данной статье я постараюсь описать некоторый минимум, необходимый для понимания возможностей регулярных выражений, а также приведу примеры задач, для решения которых я использовал регулярные выражения. Использоваться будет библиотека Python 3.7 «re» и regex101.com, также, информация из статьи. Пример работы:

import re text = ''' ИНН ., ИНН 1234567890 Инн2 - 9876543210 просто числа 1111111111 1377 ''' smf = re.search('\d', text, re.M) smf[0] if smf else 'Не найдено' 

Рассмотрим подробнее. После импорта библиотеки и создания переменной text была вызвана функция re.search(). Это одна из функций для реализации регулярных выражений в Python, принимает регулярку, ищет где нам нужно первое совпадение, флаг re.M обозначает многострочный поиск и возвращает объект re.Match с найденными координатами или None. Регулярное выражение в данном случае позволяет найти 10 чисел, идущих подряд. «\d» — это обозначение для числа, обозначает количество символов.

Отметим, что переменная text содержит в себе следующее:

\nИНН\n.,\nИНН 1234567890\nИнн2 - 9876543210\nпросто числа 1111111111\n1377\n

В Python re существуют следующие функции:

  • re.match(pattern, string, flags=0) ищет pattern в string с флагами flags, возвращает объекты match или None. Результаты можно получить как match.groups() и match.group(num=0).
  • re.search(pattern, string, flags=0) ищет pattern в string с флагами flags, возвращает первое совпадение как объект match или None.
  • re.findall(pattern, string, flags=0) ищет pattern в string с флагами flags, возвращает объекты список совпадений или пустой список.
  • re.sub(pattern, repl, string, max=0) ищет pattern в string и заменяет на repl, количество раз max, если оно указано.
  • re.I — делает поиск нечувствительным к регистру.
  • re.L — ищет слова в соответствии с текущим языком. Эта интерпретация затрагивает алфавитную группу (\w и \W), а также поведение границы слова (\b и \B).
  • re.M — символ $ выполняет поиск в конце любой строки текста (не только конце текста) и символ ^ выполняет поиск в начале любой строки текста (не только в начале текста).
  • re.S — изменяет значение точки (.) на совпадение с любым символом, включая новую строку.
  • re.U— интерпретирует буквы в соответствии с набором символов Unicode. Этот флаг влияет на поведение \w, \W, \b, \B. В python 3+ этот флаг установлен по умолчанию.
  • re.X— позволяет многострочный синтаксис регулярного выражения. Он игнорирует пробелы внутри паттерна (за исключением пробелов внутри набора [] или при экранировании обратным слешем) и обрабатывает не экранированный “#” как комментарий.
Читайте также:  Convert bytes to gigabytes python

Далее, приведена таблица с используемыми обозначениями и простыми примерами использования:

Обозначение Описание Пример в нашей строке
. любой одиночный символ, кроме «\n» «И»
\ символ для экранирования для «\.» результат – «.»
\w любая буква, цифра или «_» «И»
\d любая цифра «1»
\s любой символ пробела, табуляции, перевода строки «\n»
\b должен определять границу для \w символов, но в Python 3.7, видимо, не работает в regex101 можно было бы использовать для поиска отдельно стоящих слов/цифр, например, «\b\d\b» позволяет искать три идущих подряд цифры
* ноль или больше совпадений для «ИНН.*» результат: «ИНН»
+ одно или больше совпадений для «ИНН.+» результат: «ИНН 1234567890»
^ начало строки для «^\d+» результат: «1377»
$ конец строки для «\d+$» результат: «1234567890»
| одно или другое «а|5» — буква «а» или цифра «5»
обозначает количество искомых символов «\d» — 5 цифр,
«\d» — 3-6 цифр,
«\d» — 4 и более цифр
[ ] обозначает список символов для поиска, при этом, «^» внутри таких скобок будет означать отрицание «[дес]» — только буквы «д», «е», «с»,
«[ёа-я]» — все прописные буквы кириллицы (ё не входит в основной список),
«[^0-9]» — не цифры
() обозначает группы «(ИНН (\d))» вернёт две группы — ‘ИНН 9876543210’ и ‘9876543210’

В регулярных выражениях достаточно удобно реализованы логические отрицания, например, «\D» — это любой нецифровой символ. Аналогично и для других обозначений: «\W», «\S», «\B». Пару слов о «жадности» и «ленивости» регулярных выражений. По умолчанию, возвращается максимально длинное совпадение, например:

text = '"Рога", "Копыта" и "Ко"' re.findall('".+"', text, re.M) 

Результат: [‘»Рога», «Копыта» и «Ко»‘]

Мы хотели найти «всё внутри двойных кавычек». И нашли всё, что заключено в кавычки, как единое совпадение. Но если нужно каждое совпадение в отдельности, следует использовать «ленивый поиск»:

text = '"Рога", "Копыта" и "Ко"' re.findall('".+?"', text, re.M) 

Добавив «?» к конструкции «».+»», то есть, составив выражение «».+?»» мы получили каждое минимальное совпадение с конструкцией «всё внутри двойных кавычек».

Далее – опережающие и ретроспективные проверки или же, lookahead/lookbehind. Эти конструкции позволяют реализовать поиск чего-то после и/или до определённых выражений. То есть, мы можем, не используя группы (круглые скобки), вытащить, например, что-то между кавычек:

text = '"Рога", "Копыта" и "Ко"' re.findall('(?<=").+?(? wp-block-code">text = 'какие-то 146%, нужные проценты значение 54%, шелуха значение 987, ещё значение - 159%' re.findall('(?<=значение).+?(\d+)(?=%)', text, re.M) 

Разберём пример подробнее. Допустим, нам нужно найти в тексте число, которое следует после определённого слова (у нас – «значение»), при этом, между словом и числом может быть пробел, тире, что-то ещё, и после числа точно должен быть «%». Для понимания конструкции выше понадобится описание опережающих и ретроспективных проверок:

Если вы подумали об указании множественных условий для таких проверок, что-то вроде, (?<=значение1|значение2) то спешу разочаровать, так как re говорит нам:

«error: look-behind requires fixed-width pattern»

И это печально. Следует учитывать, что некоторые особенности регулярок могут по-разному работать в разных реализациях, поэтому стоит «обкатывать» регулярки не только на regex101, но и в самом Python.

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

«Пробенчмаркать уже это всё наконец» – тестирование инструментов для обработки данных на Python. Часть 1.

Источник

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