ОГЛАВЛЕНИЕ
1 Регулярные выражения
1.1 Синтаксис регулярных выражений
1.1.1 Представление символов
1.1.2 Позиция внутри строки
1.1.3 Квантификация (поиск последовательности)
1.1.4 Группировка
1.1.5 Перечисление
1.2 Использование регулярных выражений
1 Регулярные выражения
Регулярные выражения (англ. regular expressions, сокр. RegExp) - это формальный
язык поиска подстрок в тексте и осуществления манипуляций с ними, основанный на
использовании метасимволов (англ. wildcard characters). По сути это шаблон
(англ. pattern), строка-образец, состоящая из символов и метасимволов и
задающая правило поиска.
Регулярные выражения (РВ) изобрел американский
математик, один из основателей направления "компьютерные науки" Стефан Клини
(Stephen Kleene), который описал поведение модели нейрона, предложенной в
1940-х гг. Уорреном Маккалоком и Уолтером Питтсом, используя свою систему
математических обозначений, названную им "регулярные множества".
Регулярные выражения произвели прорыв в электронной
обработке текстов в конце XX века. Многие современные языки программирования
имеют встроенную поддержку регулярных выражений. Среди них Perl, Java, PHP,
JavaScript и многие др.
1.1 Синтаксис регулярных выражений
1.1.1 Представление символов
Регулярные выражения имеют следующие возможности представления символов:
- Большинство символов в РВ являются простыми символами
(литералами), т.е. представляют сами себя, за исключением специальных
символов [ ] \ ^ $ . | ? * + ( ) { } , которые
являются метасимволами и могут быть экранированы
(защищены) путем установки перед ними символа \ (обратная косая черта) для
представления их самих в качестве символов текста. Можно экранировать
целую последовательность символов, заключив её между \Q и \E.
- Метасимвол . (точка) в регулярном выражении означает один любой символ
(кроме символа /n - новая строка).
- Набор символов в квадратных скобках [ ] именуется символьным классом и
позволяет указать интерпретатору регулярных выражений, что на данном месте в
строке может стоять один из перечисленных символов. В частности, [abc] задает
возможность появления в тексте одного из трёх указанных символов. Можно
указать диапазон символов: например, [А-Яа-я] соответствует всем буквам русского
алфавита, за исключением букв "Ё" и "ё". Если требуется указать символы, которые
не входят в указанный набор, то используют символ ^ внутри квадратных скобок,
например [^0-9] означает любой символ, кроме цифр;
- /d - любая цифра от 0 до 9 (эквивалентно [0-9]);
- /D - любой нецифровой символ;
- /f - символ перевода страницы;
- /n- символ новой строки;
- /r- символ возврата каретки;
- /s - символы пробела, табуляции, перевода страницы, каретки и новой строки;
- /S - все, за исключением перечисленного в /s;
- /t - символ табуляции;
- /v - символ вертикальной табуляции;
- /w - буква, цифра или знак подчеркивания;
- /W - все, за исключением перечисленного в /w;
- /x{код} - символ с указанным шестнадцатиричным кодом;
- /o{код} - символ с указанным восьмиричным кодом;
- /{номер группы} - извлекает из памяти, сохраненную ранее группу символов с
заданным номером.
1.1.2 Позиция внутри строки
Следующие символы позволяют спозиционировать регулярное выражение
относительно элементов текста: начала и конца строки, границ слова:
- ^ - начало строки, т.е. проверяемый текст должен обязательно начинаться с
начала строки;
- $ - конец строки, т.е. проверяемый текст должен обязательно заканчиваться в
конце строки;
- \b - граница слова;
- \B - не граница слова.
1.1.3 Квантификация (поиск последовательности)
Квантификатор после символа, символьного класса или группы определяет,
сколько раз предшествующее выражение может встречаться (следует учитывать, что
квантификатор может относиться более чем к одному символу в регулярном выражении,
только если это символьный класс или группа):
- {n} - ровно n;
- {m,n} - от m до n включительно;
- {m,} - не менее m;
- {,n} - не более n;
- * (звезда Клини) - ноль или более;
- + - один или более;
- ? - ноль или один.
Часто используется последовательность .* для
обозначения любого количества любых символов между двумя частями регулярного
выражения.
Символьные классы в сочетании с квантификаторами
позволяют устанавливать соответствия с реальными текстами. Например, столбцами
цифр, телефонами, почтовыми адресами, элементами HTML-разметки и др.
Если символы { } не образуют квантификатор, их
специальное значение игнорируется.
1.1.4 Группировка
Для обозначения группы используются круглые скобки, которые определяют
область действия и приоритет операций. Шаблон внутри группы обрабатывается как
единое целое и может быть квантифицирован.
Одно из применений группировки - повторное
использование ранее найденных групп символов (подстрок, блоков, отмеченных
подвыражений). При обработке выражения подстроки, найденные по шаблону внутри
группы, сохраняются в отдельной области памяти и получают номер начиная с единицы.
Каждой подстроке соответствует пара скобок в регулярном выражении. Квантификация
группы не влияет на сохранённый результат, то есть сохраняется лишь первое вхождение.
Обычно поддерживается до 9 нумерованных подстрок с номерами от 1 до 9, но
некоторые интерпретаторы позволяют работать с большим количеством. Впоследствии
в пределах данного регулярного выражения можно использовать обозначения от \1 до \9
для проверки на совпадение с ранее найденной подстрокой.
Также ранее найденные подстроки можно использовать
при замене по регулярному выражению. В таком случае в замещающий текст вставляются
те же обозначения, что и в пределах самого выражения.
Если группа используется только для группировки и
ее результат в дальнейшем не потребуется, то можно использовать группировку
вида (?:шаблон). Под результат такой группировки не выделяется отдельная область
памяти и, соответственно, ей не назначается номер. Это положительно влияет на
скорость выполнения выражения, но понижает удобочитаемость.
1.1.5 Перечисление
Вертикальная черта разделяет допустимые варианты. Например, gray|grey
соответствует gray или grey. Следует помнить, что перебор вариантов выполняется
слева направо, как они указаны.
Если требуется указать перечень вариантов внутри
более сложного регулярного выражения, то его нужно заключить в группу. Например,
gray|grey или gr(a|e)y описывают строку gray или grey. В случае с односимвольными
альтернативами предпочтителен вариант gr[ae]y, так как сравнение с символьным
классом выполняется проще, чем обработка группы с проверкой на все ее возможные
модификаторы.
1.2 Использование регулярных выражений
В языке JavaScript за обработку регулярных выражений отвечает класс
RegExp. Его конструктор (форма 1):
RegExp("Регулярное выражение"
[, флаги])
имеет один обязательный параметр - регулярное выражение,
заключенное в кавычки, и один необязательный, который задает дополнительные
параметры поиска и может включать в разных сочетаниях три символа.
Символ "g" задает
глобальный поиск, т.е. поиск всех вхождений регулярного выражения в строке,
символ "i" - игнорирование регистра символов,
а символ "n" - многострочный поиск.
Например, для создания регулярного выражения,
проверяющего правильность ввода фамилии пользователя латинскими символами,
которая должна начинаться с заглавной буквы и иметь все последующие буквы
строчные, необходимо использовать следующий конструктор
re=new RegExp("^[A-Z][a-z]+$");
Символы
^ и
$ означают, что имя пользователя должно
начинаться в начале строки и заканчиваться в конце строки, т.е. ни перед,
ни после имени пользователя не должно быть никаких лишних символов.
Отсутствие квантора повторения после
[A-Z] эквивалентно использованию квантора
{1}, т.е. в этом случае заглавные символы должны
встречаться в строке только один раз. Символьный класс
[a-z] с квантором повторения + означает, что
прописных латинских букв в строке может быть одна и больше.
Доступен также такой вариант конструктора,
близкий к PERL и PHP (форма 2):
/Регулярное выражение/[флаги])
.
Его применение для того же самого РВ дает такое выражение
re=/^[A-Z][a-z]+$/;
Чтобы можно было применить регулярные выражения для решения задач проверки,
замены и поиска фрагментов текста, необходимо воспользоваться следующими
методами объекта String:
- match(регулярное выражение) - выполняет поиск в строке, используя
регулярное выражение, переданное в качестве параметра, и возвращает массив с
результатами поиска. Если ничего не найдено, возвращает null;
- replace(регулярное выражение, текст для замены) - выполняет поиск и замену
в строке, используя регулярное выражение, переданное в качестве параметра, и
возвращает строку, полученную в результате этих замен;
- search(регулярное выражение) - выполняет поиск в строке, используя
регулярное выражение, переданное в качестве параметра, и возвращает позицию
первой подстроки, совпадающей с регулярным выражением.
Класс RegExp также поддерживает три метода:
- compile("Регулярное выражение" [, флаги]) - компилирует регулярное выражежние
во внутренний формат для ускорения работы. Также может использоваться для
изменения РВ;
- exec(Строка) - аналогичен методу match класса String за тем исключением,
что принадлежит классу RegExp, а строка, где нужно произвести поиск, передается
как параметр;
- test(Строка) - аналогичен методу search класса String за тем исключением,
что принадлежит классу RegExp, а строка, где нужно произвести поиск, передается
как параметр. Возвращает или в зависимости от того, успешным ли был поиск или
нет.
В примере
№ 1 показано
применение регулярных выражений для проверки правильности ввода имени
пользователя и адреса его электронной почты (E-MAIL).
Пример 1
<HTML>
<HEAD>
<TITLE>Обработка формы с помощью регулярных выражений
JavaScript</TITLE>
<SCRIPT>
function reg()
{
if(!f.name.value)
{
alert("ВВЕДИТЕ ИМЯ И НАЖМИТЕ КНОПКУ \"ПЕРЕДАТЬ\"");
f.name.focus();
}
else
{
re=/^[A-Z][a-z]+\s[A-Z]\.$/;
re.compile(re);
if(!f.name.value.match(re))
{
alert("ИМЯ ВВЕДЕНО НЕВЕРНО. ИСПРАВЬТЕ И НАЖМИТЕ КНОПКУ \"ПЕРЕДАТЬ\"");
f.name.focus();
}
else
{
if(!f.mail.value)
{
alert("ВВЕДИТЕ E-MAIL И НАЖМИТЕ КНОПКУ \"ПЕРЕДАТЬ\"");
f.mail.focus();
}
else
{
re2=new RegExp("^(\\w+)@(\\w+(\\.\\w+)+)$");
if(!re2.exec(f.mail.value))
{
alert("E-MAIL ВВЕДЕНО НЕВЕРНО. ИСПРАВЬТЕ И НАЖМИТЕ КНОПКУ \"ПЕРЕДАТЬ\"");
f.mail.focus();
}
else if(confirm("Данные введены верно. Загрузить страницу?")) f.submit();
}
}
}
}
</SCRIPT>
</HEAD>
<BODY onLoad="f.name.focus()">
<FORM NAME="f" ACTION="js_pr4-3.htm">
<P>ВВЕДИТЕ ИМЯ:
<INPUT type=text NAME="name" value="Ivanova."><BR>;
<P>ВВЕДИТЕ E_MAIL:
<INPUT type=text NAME="mail" value="ivanov@KPI.Kharkov.ua"><BR>;
<INPUT type=reset value="СБРОС">
<INPUT type=button VALUE="ПЕРЕДАТЬ" onClick="reg()">
</FORM>
</BODY>
</HTML>
После нажатия кнопки "ПЕРЕДАТЬ" для каждого вида данных сначала проверяется,
введены ли эти данные пользователем. Если нет - выводится на экран соответствующее
сообщение.
Затем с помощью РВ проверяется соответствие
введенных данных установленному шаблону. Для имени используется описанный выше
формат. Предполагается, что данные будут вводится латинскими буквами.
Причем для проверки имени пользователя используется метод
match() объекта String, а
для проверки адреса электронной почты - эквивалентный по действию метод
exec() объекта RegExp.
Кроме того, для первого регулярного выражения
использован метод compile() объекта
RegExp для преобразования РВ во внутренний формат, что
позволяет ускорить работу с ним.
Чтобы показать, что регулярные выражения
действительно проверяют введенные данные, в имени пользователя, заданного по
умолчанию, были допущены неточности - вместо задания "Ivanov A." было задано
"Ivanova.", т.е. фамилия не отделена от имени пробелом и имя пользователя
указано с прописной буквы.
Метод match() обнаруживает эти ошибки и на экран выдается сообщение: ИМЯ ВВЕДЕНО
НЕВЕРНО. ИСПРАВЬТЕ И НАЖМИТЕ КНОПКУ "ПЕРЕДАТЬ".
После устранения обоих ошибок и нажатия кнопки
"ПЕРЕДАТЬ" на экране появляется сообщение и вопрос "Данные введены верно.
Загрузить страницу?". При положительном решении пользователя загружается
указанная Web-страница ("js_pr4-3.htm").