Регулярные выражения (regex): Простой способ описания строк

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

Что такое регулярное выражение?

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

Для каждого регулярного выражения существует конечный автомат (также известный как автомат состояний), который принимает язык, заданный выражением, и формируется из регулярного выражения с помощью алгоритма построения Томпсона. В то же время, для каждого конечного автомата существует регулярное выражение, которое описывает язык, принимаемый автоматом. Это выражение может быть получено с помощью алгоритма Клине или гауссовой элиминации.

Примечание

Автомат состояний — это модель поведения, состоящая из состояний, переходов состояний и действий. Он называется конечным, если число состояний, которые он может принимать, конечное (т.е. ограниченное).

Известным применением regex в ИТ является функция поиска и замены в текстовых редакторах, которую компьютерный пионер Кен Томпсон, один из разработчиков операционной системы UNIX, впервые реализовал в линейно-ориентированном редакторе QED в 1960-х годах, а затем в его потомке ed. Эта функция позволяет найти в тексте определенные строки и, при желании, заменить их любой другой строкой.

Определение: Регулярное выражение (regex)

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

Как работает регулярное выражение?

Регулярное выражение может быть сформировано с помощью только регулярных символов (например, abc) или с помощью комбинации регулярных символов и метасимволов (например, ab*c). Задача метасимволов — описать определенные конструкции или расположение символов, например, должен ли символ находиться в начале строки, может ли символ встречаться ровно один раз или чаще или реже. Первый пример регулярного выражения, упомянутый выше, работает следующим образом:

abc: Простой регекс-шаблон abc требует точного совпадения. Другими словами, выражение ищет все строки, содержащие символы «abc» в точном порядке. Это означает, что выражение будет соответствовать вопросу «Do you know your abcs?», а также предложению «Абкулон — это электромагнитная единица заряда».

Второй пример регулярного выражения работает следующим образом:

ab*c: В отличие от него, регулярное выражение со специальными символами работает несколько иначе, поскольку оно ищет как точные совпадения, так и специальные сценарии. В данном примере звездочка гарантирует, что выражение ищет строки, которые начинаются с буквы «a» и заканчиваются буквой «c». Однако между a и c может быть любое количество b. В результате «abc», а также строки «abbbbbc» и «cbbabbcba» также являются совпадением.

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

Каждый регекс может быть связан с определенным действием, таким как операция «replace», упомянутая выше. Это действие выполняется везде, где регулярное выражение истинно, то есть везде, где есть совпадение, как описано в примерах выше.

Какие сложности возникают при использовании regex?

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

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

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

Какие правила синтаксиса применяются к regex?

Как упоминалось ранее, regex можно использовать в различных языках, таких как Perl, Python, Ruby, JavaScript, XML или HTML, но их полезность или функции могут значительно отличаться. Например, в JavaScript шаблоны regex используются в методах поиска (), сопоставления () или замены () строк, а в XML-документах выражения используются для разграничения содержимого элементов. Однако с точки зрения синтаксиса различия между языками программирования и языками разметки практически отсутствуют, когда речь идет о regex:

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

Шаблоны Центральным элементом является паттерн, т.е. общий шаблон поиска. В качестве альтернативы, как объяснялось в предыдущем разделе, шаблон может состоять исключительно из простых символов или комбинации простых и специальных символов.
Разделители Разделители отмечают начало и конец шаблона. В качестве разделителей могут использоваться все неалфавитно-цифровые символы (кроме обратных слэшей). Например, PHP поддерживает хэштеги (#шаблон), знаки процента (%шаблон), плюсы (+шаблон+) или тильды (~шаблон~) в качестве разделителей. Однако большинство языков используют прямые кавычки («pattern») или косые черты (/pattern/).
Модификаторы Модификаторы могут быть добавлены к шаблону поиска для изменения регулярного выражения. Например, модификатор i игнорирует чувствительность к регистру. Он обеспечивает одинаковое отношение к заглавным и строчным буквам и применяется ко всем регулярным выражениям по умолчанию.

Ниже приведены типичные синтаксические символы, используемые для добавления определенных опций к шаблонам:

Специальные символы для синтаксиса regex Функция  
[] Пара квадратных скобок обозначает класс символов, который всегда представляет один символ в шаблоне поиска.  
() Пара круглых скобок обозначает группу символов, которая состоит из одного или нескольких символов и может действовать внутри друг друга.  
Указывает диапазон (от […] до […]), если он находится между двумя обычными символами  
^ Ограничивает поиск началом строки (также функционирует как отрицатель в классах символов)  
$ Ограничить поиск концом строки  
. Представляет любой символ  
* Символ, класс или группа перед звездочкой (включая ноль) может встречаться любое количество раз.  
+ Символ, класс или группа перед знаком плюс должны встречаться хотя бы один раз.  
? Символ, класс или группа перед вопросительным знаком необязательны и могут встречаться только один раз.  
    Указывает на две или более альтернатив
{n} Предшествующий символ, класс или группа встречается ровно n раз.  
{n,m} Предшествующий символ, предшествующий класс или группа встречается не менее n раз, но не более m раз.  
{n,} Предшествующий символ, класс или группа встречается n или более раз.  
b Включить край слова  
B Игнорировать край слова  
d Любая десятичная цифра; сокращение для класса символов [0-9]  
D Любой символ, не являющийся десятичной цифрой; сокращенное обозначение для класса символов [^0-9]  
w Любой буквенно-цифровой символ; краткое обозначение для класса символов [a-zA-Z_0-9]  
W Любой неалфавитно-цифровой символ; краткая нотация для класса символов [^w]  

Учебник: Пара примеров регулярных выражений для объяснения возможностей

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

Одноэлементное регулярное выражение

Простейшая форма regex — это шаблон поиска, который соответствует только одному элементу. Если вы не ищете конкретный элемент, вы можете легко определить одноэлементное регулярное выражение, используя класс символов. Следующее выражение допускает в качестве возможных совпадений цифры «1», «2», «3», «4», «5», «6» или «7»:

[1234567]

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

[1-7]

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

[1-35-7]
Примечание

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

Многоэлементное регулярное выражение

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

[1-7][a-c]

Первый элемент — число от «1» до «7», затем одна из букв «a», «b» или «c». Как уже упоминалось, нижний регистр здесь обязателен. Прежде чем вы начнете использовать модификаторы на этом этапе, вы уже можете включить заглавные буквы, внеся следующее небольшое изменение в выражение:

[1-7][a-cA-C]

Regex с необязательными элементами

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

[1-9][0-9]?[0-9]?[a-z]?

Единственным обязательным элементом в этом шаблоне поиска является цифра от «1» до «9». Далее могут следовать две цифры от «0» до «9» и любая буква, на что указывает последующий знак вопроса в каждом случае.

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

[1-9][0-9]{0,9}

Как и в предыдущем примере, выражение должно начинаться с числа от «1» до «9». Однако за этим числом может следовать либо отсутствие цифр, либо до девяти цифр между «0» и «9». Это означает, что результат поиска может состоять до десяти цифр.

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

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

[0-9]*

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

ab*

Возможные совпадения включают слова «apple», «abnormal» и «abbey». Если вы хотите исключить первое совпадение или если указанный символ встречается хотя бы один раз, вместо него следует использовать знак плюс:

ab+

Отрицание классов символов

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

F[^u]n

В этом примере вторым символом может быть любой символ, кроме «u». Поэтому в число совпадений войдет слово «Fan». Однако слово «fun» не будет совпадать, поэтому оно не относится к регулярному выражению.

Дикие символы

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

John.*Doe

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

John.+Doe

Следующий шаблон поиска соответствует и «back», и «buck» и является хорошим примером того, как использовать подстановочный знак для одного символа:

B.ck

Альтернативы

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

Tree|Flower

Это выражение найдет совпадения для слов «Дерево» и «Цветок».

Вы также можете использовать группы для формирования альтернатив внутри слов или строк:

(Sun|Mon|Tues|Wednes|Thurs|Fri|Satur)day

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

Группы

Как и классы символов, группы символов в примере из предыдущего раздела являются структурными элементами regex. Они могут быть определены парой круглых скобок и в основном представляют собой шаблон, состоящий из одного или нескольких символов. Строго говоря, каждый regex, таким образом, является группой, но в данном случае она не определяется с помощью круглых скобок. Группы позволяют применять операторы, такие как дефис или звездочка (знак плюс и звездочка), к подвыражению внутри выражений:

ab(cd)+

В данном случае желаемое неограниченное повторение применяется к группе символов «cd». Записанное в той же нотации без круглых скобок, оно применялось бы только к «d». Нет никаких ограничений на количество групп внутри regex.

Вложенные группы

Регулярное выражение может содержать не только любое количество групп. Оно также может содержать любое количество вложенных групп, чтобы выразить сложные отношения между простыми и специальными символами без излишне длинных строк. Возможные совпадения для шаблона regex в следующем примере — четыре модели автомобилей «VW Golf», «VW Jetta», «Ford Explorer» или «Ford Focus»:

(VW (Golf|Jetta)|Ford (Explorer|Focus))

Границы слов

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

Первый вариант требует, чтобы поисковая последовательность находилась в начале слова:

band

Слово «андромеда» включено в совпадения для этого примера регулярного выражения. С другой стороны, слово «band» не совпадает, потому что искомым символам предшествует буква «B». Чтобы перевернуть ситуацию, используйте второй вариант и добавьте специальные символы в конце:

andb

Наконец, в третьем варианте вы делаете обязательными обе границы слова. В этом примере единственное возможное совпадение — это связка «и».

bandb

Игнорирование мета-смысла специальных символов

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

11.10.2019

В данном случае дата «11.10.2019» является единственной символьной строкой, которая соответствует требуемым критериям поиска. Без обратной косой черты две точки интерпретируются как подстановочные знаки для любого символа, поэтому возможны такие совпадения, как «1101092019» или «11a10b2019».

«Ограничение» жадного регекса

Квантификаторы («?», «+», «*», «{}») — это метод по умолчанию, обеспечивающий «жадность» выражения и пытающийся найти самое длинное возможное совпадение. Однако, поскольку такое поведение не всегда желательно, вы можете изменить квантификаторы в регулярном выражении, чтобы сделать его менее «жадным». Следующий пример иллюстрирует процесс модификации:

A.*B

При применении к строке «ABCDEB» это жадное выражение будет включать в поиск совпадений всю строку, а не останавливать поиск после «AB». С другой стороны, если вы хотите, чтобы поиск останавливался, как только будет найдена первая буква «B», вам придется использовать вышеуказанную модификацию. Во многих языках (включая Perl, Tcl, HTML) для этой цели после квантификаторов добавляется знак вопроса:

A.*?B

В качестве альтернативы, вы можете заменить исходное жадное выражение следующим эквивалентным «нежадным» выражением, чтобы получить тот же результат:

A[^B]*B
Примечание

Ограничение жадного regex усложняет обработку поискового шаблона и увеличивает время поиска.

Оцените статью
cdelat.ru
Добавить комментарий