Дата публикации статьи: 06.07.2005 08:39

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

Что это такое?

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

С чем это едят?

Поддержка регулярных выражений есть почти в каждом языке программирования, будь то PHP, Perl, C++ или Visual Basic. Синтаксис этих регулярных выражений практически не зависит от самого языка.
Для поддержки регулярных выражений в VB подключим библиотеку Microsoft VBScript Regular expressions 5.5. И напишем следующую функцию:

Public Function ereg(ByVal nVal As String, ByRef nMask As String) As Boolean
    Static mRegExp As New VBScript_RegExp_55.RegExp
    mRegExp.Pattern = nMask
    ereg = mRegExp.Test(nVal)
End Function

Функция возвратит true, если строка nVal соответствует регулярному выражению nMask.
В PHP все еще проще: для этого есть встроенная функция ereg, которая по сути аналогична нашей функции.

Простейшее регулярное выражение

Простейшее регулярное выражение это выражение не содержащие никаких спецсимволов. Например: ABBA. Это регулярное выражение совпадает со всеми строками, выключающими в себя ABBA. Т.е. Оно совпадет со строками BABBA, ABBA, ABBAT, но не совпадет со строками ABA, BABA и т.п. Кстати говоря, регулярные выражения чувствительны к регистру. Соответственно, наше выражение не совпадет со строками BaBBA, abba и т.п.

Спецсимволы

Спецсимволы – это особые символы, которые применяются в регулярных выражениях для особых целей. К спецсимволам относятся $[]^\()| и некоторые другие. Спецсимволы нельзя применять как обычные символы. Выдумаете, что $oft совпадет со словом Micro$osft? Ошибаетесь. Это регулярное выражение вообще не с чем не совпадает(позже вы поймете, почему). А как же быть, если требуется использовать спецсимволы в их «человеческом» значении. Для этого спецсимволы надо экранировать символом \. Так, например, $ - спецсимвол, а \$ - просто знак доллара. Соответственно, регулярное выражение \$oft уже совпадает со словом Micro$osft. Еще одна из фишек символа экранирования: лексема(6) \xXX совпадает с символом, код которого XX(в шестнадцатеричной системе). Например, \xFF совпадает с символов я(код которого 255, или FF)

Символы начала и конца строки

Спецсимволы ^ и $ соответственно являются символами начала и конца строки. Например, выражение ^ABBA совпадает со словами ABBA и ABBAT, но не совпадает со словом BABBA. Выражение ABBA$ наоборот совпадает со словом BABBA, но не совпадает с ABBAT. Как вы думаете, совпадает ли ABBA$ со словом ABBA? Конечно совпадает! Ведь в слове ABBA есть символы ABBA, причем эти символы являются последними в строке. А с чем, по-вашему, совпадает выражение ^ABBA$(1)? Теперь вы поняли, почему $oft никогда ни с чем не совпадает(2)? А с чем совпадает ^$(3)?

Символы повтора и группировки

Введем еще несколько спецсимволов: *, +, ?. Эти спецсимволы ставятся после некоторого символа и означают, что этот символ
* может повторяться сколько угодно раз(от 0 до …)
+ может повторяться один раз и более
? может присутствовать один раз или отсутствовать вообще.
Соответственно: ^A?BBA*$ совпадает со словами BBA, BB, ABBA, ABB. Но не совпадает с ABBB. Выражение AB?B*A равносильно AB*A. А как можно упростить выражение ABB*A(4)? А как быть, если требуется распространить действие спецсимвола более чем на один символ? Для этого используются спецсимволы группировки: (). То бишь: в выражении ^(AB)+BA$(кстати, в чем разница с регулярным выражением (AB)+BA(5)?) действие спецсимвола + распространяется не на букву B, а на всю лексему AB. Как Вы думаете, с какой из этих строк будет совпадать это регулярное выражение: BA, ABBA, ABBAAB, ABABBA? Проверьте результат с помощью функции ereg.

Еще пара спецсимволов

Спецсимвол . совпадает с любым символом. Соответственно, выражение ^.+$ совпадает со строками ненулевой длины. Выражение ^.?$ совпадает со строками, в которых есть один символ или нет ни одного. Если функциональности символов +*? вам недостаточно, можно использовать структуру {min,max}(она называется структура диапазона). Так, например, выражение ^ab{2,5}a$ совпадает со словами abba, abbba, abbbba и abbbbba. Некоторые парсеры регулярных выражений поддерживают возможность сокращенной записи, например, запись {2} эквивалентна записи {2,2}. Очевидно, что {0,1} эквивалентно спецсимволу ? . Спецсимвол | означает выбор одного из предложенных вариантов. Например, выражение (a|b|c) совпадает с символом a, b или c. Регулярное выражение ^(ABBA|abba)$ совпадает со строкой ABBA, со строкой abba, и больше ни с чем. А какое регулярное выражение совпадает со словом ABBA, написанном в произвольном регистре (т.е. со словами Abba, AbbA, aBba и т.п.) (7)?

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

Последний аспект, который мы обсудим в этой статье – символьные классы. Символьные классы заключаются в квадратные скобки [] и записываются на своем особом мини-языке. Это очень важный момент: язык символьных классов отличается от языка регулярных выражений. Так, например, символ $ является спецсимволом в языке регулярных выражений, а вот в языке символьных классов $ - это всего лишь символ доллара. В языке символьных классов (помимо символов []) выделяются три спецсимвола: ^, - и \. Последний символ, как и в языке регулярных выражений, служит для экранирования. В простейшем варианте, в символьном классе перечисляется некоторый допустимый набор символов. Так, например, регулярное выражение ^[abcdefg]$ совпадает с любым из символов a, b, c, d, e, f или g. Символьный класс для парсера регулярных выражений – это один «символ». Просто этот «символ» такой особенный, что с ним совпадает не один символ, а сразу несколько (простите за тавтологию). Соответственно, все спецсимволы повтора, диапазона и прочие спецсимволы, которые можно применить к обычным символам можно применить и к символьным классам. С чем, по-вашему, совпадает регулярное выражение ^[abc]*$ (8)? Теперь рассмотрим два спецсимвола. Спецсимвол ^ считается спецсимволом только если он стоит в начале символьного класса. Он означает, что символьный класс «инвертированный», т.е. совпадает со всеми символами, кроме тех, которые в нем перечислены. Спецсимвол – наоборот не считается спецсимволом, когда он стоит в начале символьного класса (а считается обычным символом «минус»). Во всех остальных позициях этот спецсимвол означает «диапазон» значений. Так, например, символьный класс [A-Z] совпадает со всеми большими латинскими буквами. Символьный класс [-0-9a-zA-Z] совпадает со всеми английскими буквами, цифрами и символом «минус» (т.к., он стоит в начале нашего символьного класса). А с чем совпадает регулярное выражение ^[^A-Za-z]$ (9)?

Заключение

"Эта статья - лишь краткий экскурс в мир регулярных выражений. Некоторые возможности этой мощной технологии не были освещены в этой статье. Рекомендуем прочитать эту книгу: Дж Фридл, «Регулярные выражения» 2-е издание, изд. «Питер». Если у вас есть, что сказать автору пишите мне на e-mail.

ANDLL [andll@mail.ru]
Ответы
  1. Только со словом ABBA
  2. Потому что после конца строки по определению не может быть никаких символов.
  3. Формально: начало строки, после которого сразу следует конец строки. Фактически: только с пустой строкой, без пробелов и уж тем более символов.
  4. Формально: это означает, что в строке должен быть символ A после которого следует символ B, после которого следуют ноль или более символов B, после которого следует символ A. Соответственно «после которого следует символ B, после которого следуют ноль или более символов B» можно заменить на «после которого следует один или более символов B». Как Вы уже догадались, это AB+A.
  5. ^(AB)+BA$ совпадает со строкой только когда она ЦЕЛИКОМ совпадает с выражением (AB)+BA. В отличие от регулярного выражения (AB)+BA, с которым совпадают все строки, хотя бы часть которых совпадает с (AB)+BA. В дальнейшем я во всех примерах буду заключать наши регулярные выражения в символы ^$.
  6. лексема – часть строки, подстрока.
  7. Мы, конечно же, не будем перечислять в круглых скобках всех возможных вариантов написания слова ABBA. Таких вариантов существует 16, и наше регулярное выражение получится слишком «толстым». Мы напишем так: ^(a|A)(b|B)(b|B)(a|A)$. Или даже так: ^(a|A)(b|B){2}(a|A)$.
  8. Оно совпадает с любой строкой, в которой есть только символы a,b или c. Например: aaa, bbb, abbc, abba, accbbccbbabbbaacc. Или просто с пустой строкой. Почему? Давайте рассмотрим этот момент подробно. Квалификатор * означает, что символы могут повторяться любой количество раз, в том числе и 0 (поэтому, пустая строка тоже соответствует). Рассмотрим, к примеру, последнюю строку. Символ a соответствует классу [abc]? Соответствует. А Символ c? Соответствует. Далее, перебирая все символы, мы убеждаемся в том, что все они соответствует нашему символьному классу. А сколько таких символов? 17? А позволяет ли квалификатор *, что бы в строке было 17 символов? Позволяет! Значит, наша строка соответствует нашему регулярному выражению.
  9. Оно совпадает с любой строкой, которая содержит один символ (т.к. после символьного класса нет квалификатора повтора). Причем, этот символ не должен быть латинской буквой. Например, совпадает: % . я Ф, не совпадает: A z фф.