Регулярные выражения (regex) в python
Содержание:
- Введение в регулярные выражения
- Поиск совпадений: метод exec
- What Regular Expressions Are Exactly — Terminology
- Замена текста REGEXP_REPLACE
- Строковые методы, поиск и замена
- Примечания
- Grouping and Capturing
- 2 Практический раздел. Ссылки
- Нечёткие регулярные выражения
- 2.6 Alternation
- Синтаксис регулярных выражений
- 2.3.1 The Star
Введение в регулярные выражения
Регулярные выражения (RegExp) — это очень эффективный способ работы со строками.
Составив регулярное выражение с помощью специального синтаксиса вы можете:
- искать текст в строке
- заменять подстроки в строке
- извлекать информацию из строки
Почти во всех языках программирования есть регулярные выражения. Есть небольшие различия в реализации, но общие концепции применяются практически везде.
Регулярные выражения относятся к 1950-м годам, когда они были формализованы как концептуальный шаблон поиска для алгоритмов обработки строк.
Регулярные выражения реализованные в UNIX, таких как grep, sed и популярных текстовых редакторах, начали набирать популярность и были добавлены в язык программирования Perl, а позже и в множество других языков.
JavaScript, наряду с Perl, это один из языков программирования в котором поддержка регулярных выражений встроена непосредственно в язык.
Поиск совпадений: метод exec
Метод возвращает массив и ставит свойства регулярного выражения.
Если совпадений нет, то возвращается null.
Например,
// Найти одну d, за которой следует 1 или более b, за которыми одна d // Запомнить найденные b и следующую за ними d // Регистронезависимый поиск var myRe = /d(b+)(d)/ig; var myArray = myRe.exec("cdbBdbsbz");
В результате выполнения скрипта будут такие результаты:
Объект | Свойство/Индекс | Описания | Пример |
Содержимое . | |||
Индекс совпадения (от 0) | |||
Исходная строка. | |||
Последние совпавшие символы | |||
Совпадения во вложенных скобках, если есть. Число вложенных скобок не ограничено. | |||
Индекс, с которого начинать следующий поиск. | |||
Показывает, что был включен регистронезависимый поиск, флаг «». | |||
Показывает, что был включен флаг «» поиска совпадений. | |||
Показывает, был ли включен флаг многострочного поиска «». | |||
Текст паттерна. |
Если в регулярном выражении включен флаг «», Вы можете вызывать метод много раз для поиска последовательных совпадений в той же строке. Когда Вы это делаете, поиск начинается на подстроке , с индекса . Например, вот такой скрипт:
var myRe = /ab*/g; var str = "abbcdefabh"; while ((myArray = myRe.exec(str)) != null) { var msg = "Found " + myArray + ". "; msg += "Next match starts at " + myRe.lastIndex; print(msg); }
Этот скрипт выведет следующий текст:
Found abb. Next match starts at 3 Found ab. Next match starts at 9
В следующем примере функция выполняет поиск по input. Затем делается цикл по массиву, чтобы посмотреть, есть ли другие имена.
Предполагается, что все зарегистрированные имена находятся в массиве А:
var A = ; function lookup(input) { var firstName = /\w+/i.exec(input); if (!firstName) { print(input + " isn't a name!"); return; } var count = 0; for (var i = 0; i < A.length; i++) { if (firstName.toLowerCase() == A.toLowerCase()) count++; } var midstring = (count == 1) ? " other has " : " others have "; print("Thanks, " + count + midstring + "the same name!") }
What Regular Expressions Are Exactly — Terminology
Basically, a regular expression is a pattern describing a certain amount of text. Their name comes from the mathematical theory on which they are based. But we will not dig into that. You will usually find the name abbreviated to «regex» or «regexp». This tutorial uses «regex», because it is easy to pronounce the plural «regexes». On this website, regular expressions are highlighted in red as regex.
This first example is actually a perfectly valid regex. It is the most basic pattern, simply matching the literal text regex. A “match” is the piece of text, or sequence of bytes or characters that pattern was found to correspond to by the regex processing software. Matches are highlighted in blue on this site.
Замена текста REGEXP_REPLACE
Поиск и замена — одна из лучших областей применения регулярных выражений. Текст замены может включать ссылки на части исходного выражения (называемые обратными ссылками), открывающие чрезвычайно мощные возможности при работе с текстом. Допустим, имеется список имен, разделенный запятыми, и его содержимое необходимо вывести по два имени в строке. Одно из решений заключается в том, чтобы заменить каждую вторую запятую символом новой строки. Сделать это при помощи стандартной функции нелегко, но с функцией задача решается просто. Общий синтаксис ее вызова:
REGEXP_REPLACE (исходная_строка, шаблон ]])
Здесь исходная_строка — строка, в которой выполняется поиск; шаблон — регулярное выражение, совпадение которого ищется в исходной_строке; начальная_позиция — позиция, с которой начинается поиск; модификаторы — один или несколько модификаторов, управляющих процессом поиска. Пример:
DECLARE names VARCHAR2(60) := 'Anna,Matt,Joe,Nathan,Andrew,Jeff,Aaron'; names_adjusted VARCHAR2(61); comma_delimited BOOLEAN; extracted_name VARCHAR2(60); name_counter NUMBER; BEGIN -- Искать совпадение шаблона comma_delimited := REGEXP_LIKE(names,'^(*,)+(*){1}$', 'i'); -- Продолжать, только если мы действительно -- работаем со списком, разделенным запятыми. IF comma_delimited THEN names := REGEXP_REPLACE( names, '(*),(*),', '\1,\2' || chr(10) ); END IF; DBMS_OUTPUT.PUT_LINE(names); END;
Результат выглядит так:
Anna,Matt Joe,Nathan Andrew,Jeff Aaron
При вызове функции передаются три аргумента:
- names — исходная строка;
- ‘(*),(*),’ — выражение, описывающее заменяемый текст (см. ниже);
- ‘\1,\2 ‘ || chr(10) — текст замены. \1 и \2 — обратные ссылки, заложенные в основу нашего решения. Подробные объяснения также приводятся ниже.
Выражение, описывающее искомый текст, состоит из двух подвыражений в круглых скобках и двух запятых.
- Совпадение должно начинаться с имени.
- За именем должна следовать запятая.
- Затем идет другое имя.
- И снова одна запятая.
Наша цель — заменить каждую вторую запятую символом новой строки. Вот почему выражение написано так, чтобы оно совпадало с двумя именами и двумя запятыми. Также запятые не напрасно выведены за пределы подвыражений.
Первое совпадение для нашего выражения, которое будет найдено при вызове , выглядит так:
Anna,Matt,
Два подвыражения соответствуют именам «» и «». В основе нашего решения лежит возможность ссылаться на текст, совпавший с заданным подвыражением, через обратную ссылку. Обратные ссылки и в тексте замены ссылаются на текст, совпавший с первым и вторым подвыражением. Вот что происходит:
'\1,\2' || chr(10) -- Текст замены 'Anna,\2' || chr(10) -- Подстановка текста, совпавшего -- с первым подвыражением 'Anna,Matt' || chr(10) -- Подстановка текста, совпавшего -- со вторым подвыражением
Вероятно, вы уже видите, какие мощные инструменты оказались в вашем распоряжении. Запятые из исходного текста попросту не используются. Мы берем текст, совпавший с двумя подвыражениями (имена «Anna» и «Matt»), и вставляем их в новую строку с одной запятой и одним символом новой строки.
Но и это еще не все! Текст замены легко изменить так, чтобы вместо запятой в нем использовался символ табуляции (ASCII-код 9):
names := REGEXP_REPLACE( names, '(*),(*),', '\1' || chr(9) || '\2' || chr(10) );
Теперь результаты выводятся в два аккуратных столбца:
Anna Matt Joe Nathan Andrew Jeff Aaron
Поиск и замена с использованием регулярных выражений — замечательная штука. Это мощный и элегантный механизм, с помощью которого можно сделать очень многое.
Строковые методы, поиск и замена
Следующие методы работают с регулярными выражениями из строк.
Все методы, кроме replace, можно вызывать как с объектами типа regexp в аргументах, так и со строками, которые автоматом преобразуются в объекты RegExp.
Так что вызовы эквивалентны:
var i = str.search(/\s/) var i = str.search("\\s")
При использовании кавычек нужно дублировать \ и нет возможности указать флаги. Если регулярное выражение уже задано строкой, то бывает удобна и полная форма
var regText = "\\s" var i = str.search(new RegExp(regText, "g"))
Возвращает индекс регулярного выражения в строке, или -1.
Если Вы хотите знать, подходит ли строка под регулярное выражение, используйте метод (аналогично RegExp-методы ). Чтобы получить больше информации, используйте более медленный метод (аналогичный методу ).
Этот пример выводит сообщение, в зависимости от того, подходит ли строка под регулярное выражение.
function testinput(re, str){ if (str.search(re) != -1) midstring = " contains "; else midstring = " does not contain "; document.write (str + midstring + re.source); }
Если в regexp нет флага , то возвращает тот же результат, что .
Если в regexp есть флаг , то возвращает массив со всеми совпадениями.
Чтобы просто узнать, подходит ли строка под регулярное выражение , используйте .
Если Вы хотите получить первый результат — попробуйте r.
В следующем примере используется, чтобы найти «Chapter», за которой следует 1 или более цифр, а затем цифры, разделенные точкой. В регулярном выражении есть флаг , так что регистр будет игнорироваться.
str = "For more information, see Chapter 3.4.5.1"; re = /chapter (\d+(\.\d)*)/i; found = str.match(re); alert(found);
Скрипт выдаст массив из совпадений:
- Chapter 3.4.5.1 — полностью совпавшая строка
- 3.4.5.1 — первая скобка
- .1 — внутренняя скобка
Следующий пример демонстрирует использование флагов глобального и регистронезависимого поиска с . Будут найдены все буквы от А до Е и от а до е, каждая — в отдельном элементе массива.
var str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; var regexp = //gi; var matches = str.match(regexp); document.write(matches); // matches =
Метод replace может заменять вхождения регулярного выражения не только на строку, но и на результат выполнения функции. Его полный синтаксис — такой:
var newString = str.replace(regexp/substr, newSubStr/function)
- Объект RegExp. Его вхождения будут заменены на значение, которое вернет параметр номер 2
- Строка, которая будет заменена на .
- Строка, которая заменяет подстроку из аргумента номер 1.
- Функция, которая может быть вызвана для генерации новой подстроки (чтобы подставить ее вместо подстроки, полученной из аргумента 1).
Метод не меняет строку, на которой вызван, а просто возвращает новую, измененную строку.
Чтобы осуществить глобальную замену, включите в регулярное выражение флаг .
Если первый аргумент — строка, то она не преобразуется в регулярное выражение, так что, например,
var ab = "a b".replace("\\s","..") // = "a b"
Вызов replace оставил строку без изменения, т.к искал не регулярное выражение , а строку «\s».
В строке замены могут быть такие спецсимволы:
Pattern | Inserts |
Вставляет «$». | |
Вставляет найденную подстроку. | |
Вставляет часть строки, которая предшествует найденному вхождению. | |
Вставляет часть строки, которая идет после найденного вхождения. | |
or | Где или — десятичные цифры, вставляет подстроку вхождения, запомненную -й вложенной скобкой, если первый аргумент — объект RegExp. |
Если Вы указываете вторым параметром функцию, то она выполняется при каждом совпадении.
В функции можно динамически генерировать и возвращать строку подстановки.
Первый параметр функции — найденная подстрока. Если первым аргументом является объект , то следующие параметров содержат совпадения из вложенных скобок. Последние два параметра — позиция в строке, на которой произошло совпадение и сама строка.
Например, следующий вызов возвратит XXzzzz — XX , zzzz.
function replacer(str, p1, p2, offset, s) { return str + " - " + p1 + " , " + p2; } var newString = "XXzzzz".replace(/(X*)(z*)/, replacer)
Как видите, тут две скобки в регулярном выражении, и потому в функции два параметра , .
Если бы были три скобки, то в функцию пришлось бы добавить параметр .
Следующая функция заменяет слова типа на :
function styleHyphenFormat(propertyName) { function upperToHyphenLower(match) { return '-' + match.toLowerCase(); } return propertyName.replace(//, upperToHyphenLower); }
Примечания
Ахо А., Ульман Дж. Теория синтаксического анализа, перевода и компиляции. Синтаксический анализ. — Мир. — М., 1978. — Т. 2.
Во многих книгах используются символы ∪, + или ∨ вместо |.
Vladimir Komendantsky. Matching Problem for Regular Expressions with Variables // Trends in Functional Programming : 13th International Symposium, TFP 2012, St Andrews, UK, June 12-14, 2012, Revised Selected Papers. — Springer, 2013. — P. 149–150. — ISBN 9783642404474.
Для использования последовательностей букв необходимо установить правильную кодовую страницу, в которой эти последовательности будут идти в порядке от и до указанных символов.
Для русского языка это Windows-1251, ISO 8859-5 и Юникод, так как в DOS-855, DOS-866 и KOI8-R русские буквы не идут одной целой группой или не упорядочены по алфавиту
Отдельное внимание следует уделять буквам с диакритическими знаками, наподобие русских Ё/ё, которые, как правило, разбросаны вне основных диапазонов символов.
Существует эквивалентное обозначение ]
Существует эквивалентное обозначение ]
Grouping and Capturing
Place parentheses around multiple tokens to group them together. You can then apply a quantifier to the group. E.g. Set(Value)? matches Set or SetValue.
Parentheses create a capturing group. The above example has one group. After the match, group number one contains nothing if Set was matched. It contains Value if SetValue was matched. How to access the group’s contents depends on the software or programming language you’re using. Group zero always contains the entire regex match.
Use the special syntax Set(?:Value)? to group tokens without creating a capturing group. This is more efficient if you don’t plan to use the group’s contents. Do not confuse the question mark in the non-capturing group syntax with the quantifier.
2 Практический раздел. Ссылки
Перед тем, как использовать регулярные выражения, стоит посмотреть в документацию по вашему языку программирования и используемой библиотеке, так как диалекты обладают особенностями. Например в Perl и некоторых версиях php можно описывать рекурсивные регулярные выражения, которые не поддерживаются большинством других реализаций; механизмом флагов отличается JavaScript и так далее. Незначительными отличиями могут обладать даже различные версии одной и той же библиотеки.
Отличаются регулярные выражения не только синтаксисом, но и реализацией. Регулярные выражения — это «не просто так». Строка, задающее выражение, преобразуется в автомат, от реализации которого зависит эффективность. Масштаб проблемы хорошо иллюстрирует график зависимости времени выполнения поиска от длины строки и реализации:
Картинка взята из статьи «Поиск с помощью регулярных выражений может быть простым и быстрым«. В ней можно прочитать про различные реализации выражений, а также о том, как написать выражение так, чтобы оно работало быстрее. Кстати, так как выражение преобразуется в автомат, то зачастую его удобно визуализировать — для этого есть специальные сервисы, например. Для последнего выражения статьи будет построен такой автомат:
Примеры использования регулярных выражений:
- для валидации вводимых в поля данных: QValidator примеры использования. Ряд библиотек построения графического пользовательского интерфейса позволяют закреплять к полям ввода валидаторы, которые не позволяет ввести в формы некорректные данные. По приведенной выше ссылке можно найти валидацию номера банковской карты и номера телефона с помощью регулярных выражений библиотеки Qt. Аналогичные механизмы есть в других языках, например в Java для этого используется пакет ;
- для парсинга сайтов: Парсер сайта на Qt, использование QRegExp. В примере с сайта-галереи выбираются и скачиваются картинки заданных категорий;
- для валидации данных, передаваемых в формате JSON ряд библиотек позволяет задавать схему. При этом для строковых полей могут быть заданы регулярные выражения. В качестве упражнения можно попробовать составить выражение для пароля — проверить что строка содержит символы в разном регистре и цифры.
В сообществе Программирование и алгоритмы можно посмотреть дополнительную литературу по теме. Книгу Гойвертса и Левитана рекомендую посмотреть особенно, так как в ней по-полочкам разобраны десятки примеров, причем с учетом специфики реализации регулярных выражений в конкретных языках программирования.
Нечёткие регулярные выражения
В некоторых случаях регулярные выражения удобно применить для анализа текстовых фрагментов на естественном языке, то есть написанных людьми, и, возможно, содержащих опечатки либо нестандартные варианты употреблений слов. Например, если проводить опрос (допустим, на веб-сайте) «какой станцией метро вы пользуетесь», может оказаться, что «Невский проспект» посетители могут указать как:
- Невский
- Невск. просп.
- Нев. проспект
- наб. Канала Грибоедова («Канал Грибоедова» — это название второго выхода ст. м. Невский проспект)
Здесь обычные регулярные выражения неприменимы, в первую очередь из-за того, что входящие в образцы слова могут совпадать не очень точно (нечётко), но, тем не менее, было бы удобно описывать регулярными выражениями структурные зависимости между элементами образца,
например, в нашем случае, указать, что совпадение может быть с образцом «Невский проспект» ИЛИ «Канал Грибоедова», притом «проспект» может быть сокращено до «пр» или отсутствовать, а перед «Канал» может находиться сокращение «наб.»
Эта задача сродни полнотекстовому поиску, отличаясь в том, что здесь короткий фрагмент должен сравниваться с набором образцов, а при полнотекстовом поиске, наоборот, образец обычно один, в то время как фрагмент текста очень большой, или задаче разрешения лексической многозначности, которая, однако, не позволяет задать структурирующие отношения между элементами образца.
Существует небольшое количество библиотек, реализующих механизм регулярных выражений с возможностью нечёткого сравнения:
- TRE — бесплатная библиотека на С, использующая синтаксис регулярных выражений, похожий на POSIX (стабильный проект);
- FREJ — open-source библиотека на Java, использующая Lisp-образный синтаксис и лишённая многих возможностей обычных регулярных выражений, но сосредоточенная на различного рода автоматических заменах фрагментов текста (бета-версия).
2.6 Alternation
In regular expression Vertical bar is used to define alternation. Alternation is like a condition between multiple expressions. Now, you may be thinking that character set and alternation works the same way. But the big difference between character set and alternation is that character set works on character level but alternation works on expression level. For example, the regular expression means: uppercase character or lowercase , followed by lowercase character , followed by lowercase character or lowercase character , followed by lowercase character , followed by lowercase character .
(T|t)he|car => The car is parked in the garage.
Синтаксис регулярных выражений
Последнее обновление: 1.11.2015
Рассмотрим базовые моменты синтаксиса регулярных выражений.
Метасимволы
Регулярные выражения также могут использовать метасимволы — символы, которые имеют определенный смысл:
-
: соответствует любой цифре от 0 до 9
-
: соответствует любому символу, который не является цифрой
-
: соответствует любой букве, цифре или символу подчеркивания (диапазоны A–Z, a–z, 0–9)
-
: соответствует любому символу, который не является буквой, цифрой или символом подчеркивания (то есть не находится в следующих диапазонах A–Z, a–z, 0–9)
-
: соответствует пробелу
-
: соответствует любому символу, который не является пробелом
-
: соответствует любому символу
Здесь надо заметить, что метасимвол \w применяется только для букв латинского алфавита, кириллические символы для него не подходят.
Так, стандартный формат номера телефона соответствует регулярному выражению .
Например, заменим числа номера нулями:
var phoneNumber = «+1-234-567-8901»; var myExp = /\d-\d\d\d-\d\d\d-\d\d\d\d/; phoneNumber = phoneNumber.replace(myExp, «00000000000»); document.write(phoneNumber);
Модификаторы
Кроме выше рассмотренных элементов регулярных выражений есть еще одна группа комбинаций, которая указывает, как символы в строке будут повторяться. Такие комбинации еще называют модификаторами:
-
: соответствует n-ому количеству повторений предыдущего символа. Например, соответствует подстроке «hhh»
-
: соответствует n и более количеству повторений предыдущего символа. Например, соответствует подстрокам «hhh», «hhhh», «hhhhh» и т.д.
-
: соответствует от n до m повторений предыдущего символа. Например, соответствует подстрокам «hh», «hhh», «hhhh».
-
: соответствует одному вхождению предыдущего символа в подстроку или его отсутствию в подстроке. Например, соответствует подстрокам «home» и «ome».
-
: соответствует одному и более повторений предыдущего символа
-
: соответствует любому количеству повторений или отсутствию предыдущего символа
-
: соответствует началу строки.
Например, соответствует строке «home», но не «ohma», так как h должен представлять начало строки
-
: соответствует концу строки. Например, соответствует строке «дом», так как строка должна оканчиваться на букву м
Например, возьмем номер тот же телефона. Ему соответствует регулярное выражение . Однако с помощью выше рассмотренных комбинаций мы его можем упростить:
Также надо отметить, что так как символы ?, +, * имеют особый смысл в регулярных выражениях, то чтобы их использовать в обычным для них значении (например, нам надо заменить знак плюс в строке на минус), то данные символы надо экранировать с помощью слеша:
var phoneNumber = «+1-234-567-8901»; var myExp = /\+\d-\d{3}-\d{3}-\d{4}/; phoneNumber = phoneNumber.replace(myExp, «80000000000»); document.write(phoneNumber);
Отдельно рассмотрим применение комбинации ‘\b’, которая указывает на соответствие в пределах слова. Например, у нас есть следующая строка: «Языки обучения: Java, JavaScript, C++». Со временем мы решили, что Java надо заменить на C#. Но простая замена приведет также к замене строки «JavaScript» на «C#Script», что недопустимо. И в этом случае мы можем проводить замену, если регуляное выражение соответствует всему слову:
var initialText = «Языки обучения: Java, JavaScript, C++»; var exp = /Java\b/g; var result = initialText.replace(exp, «C#»); document.write(result); // Языки обучения: C#, JavaScript, C++
Но при использовании ‘\b’ надо учитывать, что в JavaScript отсутствует полноценная поддержка юникода, поэтому применять ‘\b’ мы сможем только к англоязычным словам.
Использование групп в регулярных выражениях
Для поиска в строке более сложных соответствий применяются группы. В регулярных выражениях группы заключаются в скобки. Например, у нас есть следующий код html, который содержит тег изображения: ‘<img src=»https://steptosleep.ru/wp-content/uploads/2018/06/47616.png» />’. И допустим, нам надо вычленить из этого кода пути к изображениям:
var initialText = ‘<img src= «picture.png» />’; var exp = /+\.(png|jpg)/i; var result = initialText.match(exp); result.forEach(function(value, index, array){ document.write(value + «<br/>»); })
Вывод браузера:
picture.png png
Первая часть до скобок (+\.) указывает на наличие в строке от 1 и более символов из диапазона a-z, после которых идет точка. Так как точка является специальным символом в регулярных выражениях, то она экранируется слешем. А дальше идет группа: . Эта группа указывает, что после точки может использоваться как «png», так и «jpg».
2.3.1 The Star
The symbol matches zero or more repetitions of the preceding matcher. The regular expression means: zero or more repetitions of preceding lowercase character . But if it appears after a character set or class then it finds the repetitions of the whole character set. For example, the regular expression means: any number of lowercase letters in a row.
* => The car parked in the garage #21.
The symbol can be used with the meta character . to match any string ofcharacters . The symbol can be used with the whitespace character to match a string of whitespace characters. For example, the expression means: zero or more spaces, followed by lowercase character ,followed by lowercase character , followed by lowercase character , followed by zero or more spaces.
\s*cat\s* => The fat cat sat on the concatenation.