- PVSM.RU - https://www.pvsm.ru -
Здравствуйте, уважаемые дамы и господа.
Мы активно ищем свежую литературу на тему регулярных выражений для начинающих. Причем в данном случае нас бы скорее привлекла не переводная, а исходно русскоязычная книга, которая каким-то образом затрагивала бы и регулярные выражения при обработке естественного языка. Хотим предложить вашему вниманию следующий текст — во-первых, напомнить об этой теме, во-вторых, продемонстрировать примерный уровень сложности, который нас интересует
Рано или поздно вам придется иметь дело с регулярными выражениями. Притом, какой у них сложный синтаксис, путаная документация и жесткая кривая обучения, большинство разработчиков удовлетворяются следующим: копипастят выражение со StackOverflow и надеются, что оно будет работать. Но что если бы в самом деле могли расшифровывать регулярные выражения и пользоваться ими на всю катушку? В этой статье я расскажу, почему следует еще раз присмотреться к регулярным выражениям, и как они могут пригодиться на практике.
Зачем нужны регулярные выражения?
Зачем вообще возиться с регулярными выражениями? Чем они могут помочь именно вам?
text.replace(/s+/g, " ")
заменяет все пробелы в text, например, " nt "
, одним пробелом.name.matches(/^(Mr|Ms|Mrs|Dr).?s/i)[1]
извлекает из строки обращение к человеку, например, "Mr"
из "Mr. Schropp"
.Как писать регулярные выражения
Регулярные выражения проще всего изучить на примере. Допустим, вы пишете веб-страницу, на которой будет поле для ввода телефонного номера. Поскольку вы — ас веб-разработки, вам хочется дополнительно отображать на экране галочку, если телефонный номер валиден, и крестик X — если нет.
<input id="phone-number" type="text">
<label class="valid" for="phone-number"><img src="check.svg"></label>
<label class="invalid" for="phone-number"><img src="x.svg"></label>
input:not([data-validation="valid"]) ~ label.valid,
input:not([data-validation="invalid"]) ~ label.invalid {
display: none;
}
$("input").on("input blur", function(event) {
if (isPhoneNumber($(this).val())) {
$(this).attr({ "data-validation": "valid" });
return;
}
if (event.type == "blur") {
$(this).attr({ "data-validation": "invalid" });
}
else {
$(this).removeAttr("data-validation");
}
});
Теперь, если человек введет или вставит в поле валидный номер, то отобразится галочка. Если пользователь уберет курсор из поля ввода, а в поле при этом останется недопустимое значение, то отобразится крестик.
Поскольку вы знаете, что телефонные номера состоят из десяти цифр, первым делом проверяете, чтобы isPhoneNumber
выглядел так:
function isPhoneNumber(string) {
return /dddddddddd/.test(string);
}
В этой функции между символами / содержится регулярное выражение с десятью d'
, то есть, символами-цифрами. Метод test
возвращает true
, если регулярное выражение соответствует строке, в противном случае – false
. Если выполнить isPhoneNumber("5558675309")
, метод вернет true
! Ура!
Однако, писать десять d
– слегка муторная работа. К счастью, то же самое можно сделать и при помощи фигурных скобок.
function isPhoneNumber(string) {
return /d{10}/.test(string);
}
Иногда, вводя телефонный номер, человек начинает с ведущей 1. Правда было бы неплохо, если бы ваше регулярное выражение обрабатывало и такие случаи? Это можно сделать при помощи символа?.
function isPhoneNumber(string) {
return /1?d{10}/.test(string);
}
Символ ?
означает «ноль или единица», поэтому теперь isPhoneNumber
возвращает true
как для «5558675309», так и для «15558675309»!
Пока isPhoneNumber
вполне хороша, но мы упускаем одну ключевую деталь: регулярные выражения сплошь и рядом могут совпадать не со строкой, а с частью строки. Оказывается, isPhoneNumber("555555555555555555")
возвращает true, поскольку в этой строке десять цифр. Проблему можно решить, воспользовавшись якорями ^ и $.
function isPhoneNumber(string) {
return /^1?d{10}$/.test(string);
}
Грубо говоря, ^ соответствует началу строки, а $ — концу строки, поэтому теперь ваше регулярное выражение совпадет с целым телефонным номером.
Серьезный пример
Релиз страницы состоялся, она пользуется бешеным успехом, но есть существенная проблема. В США телефонный номер можно записать разными способами:
Хотя пользователи и могут обойтись без пунктуации, им было бы гораздо проще вводить заранее отформатированный номер.
Пусть вы и могли бы написать регулярное выражение для обработки всех этих форматов, думаю, что это плохая идея. Как бы тщательно вы ни старались учесть все форматы, все равно какой-нибудь пропустите. Кроме того, в действительности вам интересны только сами данные, а не их форматирование. Итак, чем возиться со всей этой пунктуацией, не проще ли избавиться от нее?
function isPhoneNumber(string) {
return /^1?d{10}$/.test(string.replace(/D/g, ""));
}
Функция replace заменяет пустой строкой символ D
, соответствующий любым символам кроме цифр. Глобальный флаг g
приказывает функции заменить на регулярное выражение все совпадения, а не только первое.
Еще более серьезный пример
Ваша страница с телефонными номерами всем нравится, в офисе вы – король кулера. Однако, такие профессионалы как вы не останавливаются на достигнутом, поэтому вы хотите сделать страницу еще лучше.
North American Numbering Plan [1] – это стандарт по составлению телефонных номеров, используемый в США, Канаде и еще 23 странах. В этой системе есть несколько простых правил:
Ваше регулярное выражение уже соответствует первому правилу, но нарушает второе и третье. Пока давайте разберемся со вторым. Новое регулярное выражение должно выглядеть примерно так:
/^1?<AREA CODE><EXCHANGE CODE><SUBSCRIBER NUMBER>$;/
Номер абонента прост, он состоит всего из четырех цифр
/^1?<AREA CODE><EXCHANGE CODE>d{4}$/
Региональный код немного сложнее. Нас интересует цифра от 2 до 9, за которой идут еще две цифры. Для этого можно использовать символьное множество! Символьное множество позволяет задать группу символов, из которых затем можно выбирать.
/^1?[23456789]dd<EXCHANGE CODE>d{4}$/
Отлично, но мы устанем вручную вводить все символы от 2 до 9. Сделаем код еще чище при помощи символьного диапазона.
/^1?[2-9]dd<EXCHANGE CODE>d{4}$/
Уже лучше! Поскольку региональный код такой же, как и код АТС, можно просто продублировать регулярное выражение, чтобы довести этот шаблон до ума.
/^1?[2-9]dd[2-9]ddd{4}$/
А как сделать, чтобы не приходилось копировать и вставлять ту часть выражения, в которой содержится региональный код? Все упростится, если использовать группу! Чтобы сгруппировать символы, их нужно просто заключить в круглые скобки.
/^1?([2-9]dd){2}d{4}$/
Итак, [2-9]dd
содержится в группе, а {2}
указывает, что эта группа должна фигурировать дважды.
Вот и все! Рассмотрим окончательный вариант функции
isPhoneNumber
:
function isPhoneNumber(string) {
return /^1?([2-9]dd){2}d{4}$/.test(string.replace(/D/g, ""));
}
Когда лучше обходиться без регулярных выражений
Регулярные выражения – отличная штука, просто не следует решать с их помощью некоторые задачи.
Не будьте слишком строги. Нет никакого смысла проявлять чрезмерную строгость, когда пишешь регулярные выражения. В случае с телефонными номерами, даже если мы учтем все правила из документа NANP, все равно невозможно определить, реален ли данный телефонный номер. Если я заделаю номер(555) 555-5555, то он совпадет с шаблоном, но ведь такого телефонного номера не существует.
Не пишите HTML-парсер. Хотя регулярные выражения отлично подходят для парсинга каких-то простых вещей, синтаксический анализатор для целого языка из них не сделаешь. Если вы не любите заморачиваться [2], то вам вряд ли понравится разбирать нерегулярные языки при помощи регулярных выражений.
Не используйте их с очень сложными строками. Полное регулярное выражение [3] для работы с электронной почтой состоит из 6 318 символов. Простое и приблизительное выглядит так: /^[^@]+@[^@]+.[^@.]+$/
. Общее правило таково: если у вас получается регулярное выражение длиннее одной строки кода, то, возможно, стоит поискать другое решение.
Автор: Издательский дом «Питер»
Источник [4]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/programmirovanie/120772
Ссылки в тексте:
[1] North American Numbering Plan: https://en.wikipedia.org/wiki/North_American_Numbering_Plan
[2] заморачиваться: https://en.wikipedia.org/wiki/Regular_expression#Patterns_for_non-regular_languages
[3] Полное регулярное выражение: http://www.ex-parrot.com/pdw/Mail-RFC822-Address.html
[4] Источник: https://habrahabr.ru/post/300892/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best
Нажмите здесь для печати.