Javascript, регулярное выражение: примеры, проверка регулярных выражений
До появления языков гипертекста, а скорее, до того момента, как стало ясным, что нужно не только искать, но и делать это при определенных условиях, в конкретном месте, при изменившихся данных, в нужных количествах, обычные функции поиска и замены устраивали любого искушенного программиста. Создавались шедевры поискового искусства на языках программирования, а базы данных изощрялись в формах условий выборки, оснащались хранимыми процедурами, триггерами и другими средствами выборки из громоздких реляционных информационных композиций. Появление регулярных выражений к революции не привело, но оказалось полезным и удобным средством для поиска и замены информации. Например, регулярные выражения JavaScript email существенно упрощают регистрацию посетителей, не загружают сайт отправкой сообщений по несуществующим адресам.
Сказать, что на JavaScript регулярное выражение значительно лучше продуманнных последовательностей вызовов indexOf() в обрамлении условных и циклических операторов, нельзя, но утверждать, что оно сделало код скрипта компактным, но слабо понятным непосвященному, можно однозначно.
Объект RegExp = шаблон + движок
Регулярные выражения - это шаблон + движок. Первое есть собственно регулярное выражение – объект JavaScript - RegExp, второе - это исполнитель шаблона, применяющий его к строке. Движки, реализующие регулярные выражения для каждого языка программирования, отличаются. И хотя не все отличия существенны, это нужно иметь в виду, равно как и обязательно тщательно проверять регулярное выражение перед его эксплуатацией.
Особая нотация при написании регулярных выражений вполне удобна и достаточно эффективна, но требует внимательности, аккуратности и терпения от разработчика. К нотации шаблонов регулярных выражений нужно привыкнуть. Это не дань моде, это логика реализации механизма «JavaScript регулярные выражения».
Шаблон регулярного выражения
Допускается два варианта:
var expOne = /abc*/i;
var expTwo = RegExp(“abc*”, “i”);
Обычно используется первый способ. Во втором случае применяются кавычки, потому для использования символа '\', его нужно экранировать по общим правилам.
'i' - флаг, обозначающий «регистр не важен». Можно использовать также флаги 'g' - «глобальный поиск» и 'm' - многострочный поиск.
Символ '/' принято использовать для обозначения шаблона.
Начало и конец регулярного выражения
Символ '^' определяет символ(ы), с которого начинается регулярное выражение, а '$' определяет какой символ(ы) должен быть в конце. Не следует экспериментировать с ними внутри выражения, там у них иной смысл.
Например,
var eRegExp = new RegExp(cRegExp, 'i');
var cRegRes = '';
var sTest = 'AbcZ';
if (eRegExp.test(sTest)) {
cRegRes += ' - Yes';
} else {
cRegRes += ' - No';
}
var dTestLine = document.getElementById('scTestLine');
dTestLine.innerHTML = 'Выражение /'+cRegExp+'/ для строки "'+ sTest+'"'+cRegRes.
В элементе 'scTestLine' будет результат (переменная cRegExp имеет соответствующее значение):
выражение /^AbcZ$/ для строки "abcz" - Yes
Если убрать флаг 'i', то результат будет:
выражение /^AbcZ$/ для строки "abcz" - No
Содержание регулярного выражения
Регулярное выражение есть последовательность символов, которая является предметом поиска. Выражение /qwerty/ ищет вхождение именно этой последовательности:
выражение /qwerty/ для строки "qwerty" - Yes
выражение /qwerty/ для строки "123qwerty456" - Yes
Символ '^' меняет суть выражения:
выражение /^qwerty/ для строки "123qwerty456" – No
выражение /^qwerty/ для строки "qwerty456" - Yes
Аналогично для символа конца строки. Регулярные выражения допускают последовательности: например, [a-z], [A-Z], [0-9] - все буквы латинского алфавита в указанном регистре или цифры. Русские буквы тоже допускается использовать, однако следует обращать внимание на кодировку строк (где ищется, что ищется) и страницы. Часто русские буквы, как и специальные символы, предпочтительно задавать кодами.
При формировании регулярного выражения можно указывать варианты наличия тех или иных символов в определенном месте, при этом их количество задается так: '*' = повторение 0 или более раз; '+' = повторение 1 или более раз; {1,} то же, что и '+'; {n} = повторение ровно n раз; {n,} = повторение n и более раз; {n,m} = повторение от n до m раз.
Используя квадратные скобки, можно указать варианты символа из набора. Это выглядит так. [abcd] = [a-d] = любой символ из четырех: 'a', 'b', 'c' или 'd'. Можно указать обратное. Любой символ, кроме указанных в наборе: [^abcd] = любой символ кроме 'a', 'b', 'c' или 'd'. '?' указывает, что в данном месте символа может и не быть. '.' определяет любой символ, кроме обозначающего перевод строки. Это '\n', '\r', '\u2028' или '\u2029'. Выражение '\s*|\S*' = '[\s|\S]*' означает поиск любого символа, включая переводы строк.
Упрощенные варианты регулярного выражения
Выражение '[\s|\S]*' - поиск пробела или его отсутствия, то есть всего, что есть в строке. В данном случае обозначение '\s' означает пробел, а '\S' - его отсутствие.
Аналогично можно использовать '\d' для поиска десятичной цифры, а '\D' найдет нецифровой символ. Обозначения '\f', 'r' и '\n' соответствуют form-feed, carriage return и line-feed.
Символ табуляции – '\t', вертикальной – '\v'. Обозначение '\w' найдет любой символ латинского алфавита (буквы, цифры, знак подчеркивания) = [A-Za-z0-9_].
Обозначение '\W' эквивалентно [^A-Za-z0-9_]. Это означает любой символ, который не является буквой латинского алфавита, цифрой или знаком '_'.
Поиск символа '\0' = поиск символа NUL. Поиск '\xHH' или '\uHHHH' = поиск символа с кодом HH или HHHH соответственно. H - шестнадцатеричная цифра.
Рекомендуемая формулировка и кодировка регулярного выражения
Любое регулярное выражение важно внимательно тестировать на разных вариантах строк.
С опытом создания регулярных выражений ошибок будет меньше, но тем не менее следует всегда иметь в виду, что собственные знания по правилам написания регулярного выражения могут не соответствовать действительности, особенно когда «регулярка» переносится с одного языка на другой.
Выбирая между классикой (точное указание) и упрощенным вариантом регулярного выражения, лучше предпочесть первую. Ведь в классике всегда четко обозначено, что и как ищется. Если в регулярном выражении или в строке поиска есть русские буквы, следует привести к единой кодировке все строки и страницу, на которой функционирует JavaScript-код, выполняющий регулярное выражение.
Когда идет обработка символов, не принадлежащих латинскому алфавиту, имеет смысл рассмотреть указание кодов символов, а не самих символов.
При реализации алгоритмов поиска на JavaScript регулярное выражение следует тщательно проверять. Особенно важно контролировать кодировку символов.
Скобки в регулярных выражениях
Квадратные скобки задают варианты символа, который должен находиться или отсутствовать в определенном месте, а круглые – варианты последовательностей. Но это только общее правило. Из него нет исключений, но есть множество разнообразных вариантов применений.
var cRegExp = "[a-z]*.(png|jpg|gif)";
var eRegExp = new RegExp(cRegExp, 'i');
var cRegRes = '';
var sTest = 'picture.jpg';
if (eRegExp.test(sTest)) {
cRegRes += ' - Yes';
} else {
cRegRes += ' - No';
}
Результаты:
выражение /[a-z]*.(png|jpg|gif)/ для строки "picture.jpg" - Yes
выражение /^[a-d][a-z]*.(png|jpg|gif)/ для строки "picture.jpg" – No
выражение /^[a-d][a-z]*.(png|jpg|gif)/ для строки "apicture.jpg" - Yes
выражение /^[a-d][a-z]*.(png|jpg|gif)/ для строки "apicture.jg" - No
Следует особо отметить, что все, после чего стоит звездочка, может присутствовать ноль раз. Это означает, что «регулярка» может сработать самым неожиданным образом как минимум.
Проверка RegExp - тестирование email
На JavaScript регулярные выражения получают два метода, test и exec, и могут быть использованы в объектах строк (String) в их методах (функциях): search, split, replace и match.
Метод test уже был продемонстрирован, он позволяет проверить правильность регулярного выражения. Результат метода: true/false.
Рассмотрим следующие регулярные выражения JavaScript. Проверка email из числа «сложно, но точно»:
var eRegExp = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
для строки var sTest ='SlavaChip@sci.by' дает true, то есть данная строка является правильным email-адресом. Проверка была проведена методом eRegExp.test(sTest).
Практическое использование: обработка e-Mail
Метод exec на выходе предоставляет массив, вызов:
var aResult = eRegExp.exec(sTest);
cRegRes = '<br/>' + aResult.length + '<br/>';
for (var i=0; i<aResult.length; i++) {
cRegRes += aResult[i] + '<br/>';
}
дает такой результат:
9
Slava.Chip@sci.by
Slava.Chip
Slava.Chip
.Chip
undefined
sci.by
undefined
sci.by
sci.
Остальные методы работают аналогично. Рекомендуется проверить их самостоятельно. Разработку и использование регулярных выражений желательно отработать на практике, копирование кода не всегда здесь целесообразно.
Популярные «регулярки»
Приведенное JavaScript регулярное выражение для eMail не единственное, есть множество более простых вариантов. Например, /^[\w-\.]+@[\w-]+\.[a-z]{2,3}$/i. Однако этот вариант учитывает не все варианты записи электронного адреса.
Безусловно, необходимо просматривать опыт коллег, анализировать предлагаемые ими способы, прежде чем проектировать собственное на JavaScript регулярное выражение. Но есть и определенные сложности. Не следует забывать, что на JavaScript регулярные выражения (примеры их при копировании) могут продублировать существенные символы: '\', '/' или кавычки. Это приведет к ошибке, которую можно долго искать.
Важно учитывать привычный «человеческий аспект». Ведь формальное JavaScript регулярное выражение для телефона, который может быть посетителем (человеком), бывает указано различными способами: 123-45-67, (29) 1234567, 80291234567 или +375291234567. И это все один и тот же номер. Вариант написания нескольких шаблонов не всегда приемлем, а жесткая фиксация правила для написания номера может создать ненужное неудобство или ограничения. Вариант /^\d[\d\(\)\ -]{4,14}\d$/i годится для большинства случаев проверки номера телефона.
Если необходимо составить JavaScript регулярные выражения, только цифры проверяющее, то даже такой простой случай требует уточнений. Он должен рассматривать целое число или дробное, экспоненциальную запись или обычную, положительное число или отрицательное. Можно учитывать также наличие символа валюты, число цифр после запятой и разделение целой части числа на триады.
Выражение /^\d+$/i проверит только цифры, а выражение /^\d+\.\d+$/i позволяет использовать точку для указания дробной части числа.
В JavaScript проверка регулярных выражений может быть использована для жесткого указания формата вводимых данных, что актуально, в частности при вводе анкет, паспортных данных, юридических адресов и т. д.
Проверка даты - просто о сложном
Рассмотрим еще JavaScript регулярные выражения. Примеры для даты, как и для числа или номера телефона представляют собой выбор между жесткостью и гибкостью. Дата события - одно из существенных данных, которые часто приходится вводить. Но фиксация ввода в определенном формате: 'дд-мм-гггг' или 'д.м.гг' часто приводит к недовольству клиента. Переход от поля ввода дня к месяцу, исполненный классической HTML-формой, может не состояться при вводе только одной цифры, а ввод второй может вызвать затруднения. Например, в поле дня было уже введено 3, а следующая цифра 2 не замещает первую, и приписывается к ней 32, что, естественно, вызовет неудобство.
Эффективность и удобство регулярных выражений существенно зависят от общего построения диалога с посетителем. В одном случае для указания даты целесообразно использовать одно поле ввода формы, в другом случае нужно предусмотреть различные поля для дня, месяца и года. Но тогда возникнут дополнительные «расходы кода» на проверку високосного года, числа месяцев, количества дней в них.
Поиск с заменой, память регулярного выражения
JavaScript replace (регулярные выражения) используют метод объекта String и позволяют находить значение и сразу его изменять. Это удобно для исправления ошибок ввода, редактирования содержимого полей форм и для преобразования данных из одного формата представления в другой.
var cRegExp = /([а-я]+)\s([а-я]+)\s([а-я]+)/i; // при поиске создаются три 'переменных'
var sTest = 'эта статья хорошая!';
var cRegRes = sTest.replace(cRegExp, "$2, $3, $1");
var dTestLine = document.getElementById('scTestLine');
dTestLine.innerHTML = 'Выражение '+cRegExp+' для строки "'+ sTest+'" получится: '+cRegRes;
Результат:
выражение /([а-я]+)\s([а-я]+)\s([а-я]+)/i для строки "эта статья хорошая!" получится: статья, хорошая, эта!
При выполнении каждая пара круглых скобок запоминает результат в 'переменной' $n, где n - номер пары скобок ($1, $2, ...). В отличие от общепринятой, здесь нумерация переменных ведется с 1, а не с 0.
Общие рекомендации
Регулярное выражение упрощает код, но время на его разработку часто имеет значение. Можно начинать работу с простых конструкций, потом объединять сделанное в более сложные выражения. Можно использовать различные онлайн-сервисы для проверки регулярных выражений или специальные локальные инструментальные средства.
Лучшим вариантом останется создание собственной библиотеки регулярных выражений и собственного инструмента для проверки новых разработок. Это лучший способ закрепить опыт и научиться быстро создавать надежные и удобные конструкции.
Используя повторения символов и строк, то есть специальные символы '*', '+' и фигурные скобки, указывающие количества повторов, следует руководствоваться принципами простоты и целесообразности. Важно понимать, что регулярное выражение с момента начала его работы и до получения результата всецело во власти движка используемого браузера. Не все языки JavaScript эквивалентны. Каждый браузер может привнести свои личные предпочтения в интерпретации регулярных выражений.
Совместимость касается не только страниц и таблиц стилей, к регулярным выражениям она также имеет отношение. Страница, использующая JavaScript, может считаться отлаженной, только когда она успешно отработала на различных браузерах.
JavaScript, String и RegExp
По праву работа на уровне клиента, то есть в браузере посетителя на языке JavaScript, требует высокой квалификации от разработчика. Достаточно давно появилась возможность отлаживать JavaScript-код собственными средствами браузера или при помощи сторонних расширений, редакторов кода, независимых программ.
Однако далеко не во всех случаях отладчик может управиться и обеспечить разработчику хорошую поддержку, быстрое определение ошибок, обнаружение узких мест. Времена, когда компьютер был ориентирован на вычисления, в далеком прошлом. Теперь особое внимание уделяют информации, и объекты строк стали играть существенную роль. Числа стали строками, а свою истинную сущность они проявляют только в нужное время и в нужном месте.
Регулярные выражения усиливают возможности строк, но требуют к себе должного уважения. Отлаживать RegExp в процессе его работы, даже если это возможно смоделировать, не слишком интересная затея.
Понимание структуры и логики объекта RegExp, смысла объекта String, синтаксиса и семантики JavaScript - верная гарантия безопасного и надежного кода, стабильной работы каждой страницы и сайта в целом.