Как стать автором
Обновить

Комментарии 55

Очень подробная статья и много примеров, да еще и все в одном месте, спасибо. Для новичка действительно может быть полезным стартом.
Спасибо! :)
Не надо регулярно выражаться при самых маленьких.
Мы выбираем все, что не пробел (потому что первая часть email может содержать любой набор символов)
… включая пробел.
"name with spaces"@example.com
Вообще, imho не надо учить новичков проверять email regexp-ами.
Да, Вы совершенно правы, спасибо. В таком случае имя пользователя должен находиться в кавычках, насколько я помню. С этим примером наша регулярка не справится.

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

В дальнейшем, конечно, такие вещи, как работа с email или URL стоит гуглить, интересоваться стандартами и типовыми решениями.
Понятно, что это лишь пример. Просто новички часто берут примеры сразу в работу, не читая особо текст с предупреждениями о RFC и т.п… Случай email вообще — особенный. Казалось бы он достаточно нагляден, но
В дальнейшем, конечно, такие вещи, как работа с email или URL стоит гуглить, интересоваться стандартами и типовыми решениями.
А правильные типовые решения скорее всего такие:
Невозможно проверить адрес e-mail на допустимость с помощью регулярных выражений
или
Прекратите проверять Email с помощью регулярных выражений!
Раз уж завязалась дискуссия, стоит определиться с целью, которую мы преследуем, проверяя email.

Если мы делаем это, чтобы вычислить 100% возможных вариантов (например, с целью заспамить онные), то нам действительно стоит позаботиться о том, чтобы не пропустить даже те, необычные, которые с пробелом.

Если же мы работаем на массовую аудиторию и наша задача — подсказать пользователю, что он, возможно, ошибся с введением своего email, то эту задачу мы вполне себе решим без чрезмерного уровня дотошности.

Тот же Gmail не даст так просто зарегистрировать email с пробелом, вот его сообщение об ошибке:
Некорректное имя почтового ящика. Допустимо использовать только латинские буквы, цифры,
знак подчеркивания («_»), точку («.»), минус («-»)


А вот ответ Yandex:
Логин может состоять из латинских символов, цифр, одинарного дефиса или точки. Он должен начинаться с буквы, заканчиваться буквой или цифрой и содержать не более 30 символов.


Ответ Mail:
Некорректное имя почтового ящика. Допустимо использовать только латинские буквы, цифры,
знак подчеркивания («_»), точку («.»), минус («-»)


Ответ Yahoo:
Имя пользователя может содержать только буквы, цифры, точки (.) и символы подчеркивания (_).


Даже если к нам придет пользователь с некорректным email, который он себе как-то сделал, мы напишем ему, что следует завести другой email ради нашего сервиса. Но это менее 0.(0)1%.

Зато мы заранее предупредим остальных 99.(9)% пользователей о возможной опечатке, чтобы им не пришлось проходить этап регистрации дважды.

Я это к тому, что в погоне за «абсолютной правильностью» важно понимать, какую задачу мы решаем. И не подменять ее на другую, абстрактную.
Я это к тому, что в погоне за «абсолютной правильностью» важно понимать, какую задачу мы решаем. И не подменять ее на другую, абстрактную.

Вы в статье рассматриваете абстрактные примеры валидации email, и именно в этом абстрактном контексте я и беседую. Поэтому не надо в рамках данной дискуссии подменять абстрактную задачу на какую-то конкретную.

Поясню. Примеры с Яндексом и т.д. совсем не в тему. Это примеры систем со своими требованиями и ограничениями к формату email адреса и именно эти свои требования они проверяют. Это пример как раз конкретной задачи с определенными ограничениями.

Поэтому если бы в вашей статье пример выглядел так:
«Давайте проверим email пользователя Яндекс — логин может состоять из латинских символов, цифр, одинарного дефиса или точки. Он должен начинаться с буквы, заканчиваться буквой или цифрой и содержать не более 30 символов.»
то мне был бы понятен ваш аргумент, однако в таком случае и этой дискуссии бы не было.

Вы же в статье пишите о RFC
На самом деле есть RFC, который определяет правильность email. И есть “регулярки” по RFC — вот примеры.
и якобы (примеры по ссылке — тоже работают неправильно) существующей возможности проверки email адреса регулярным выражением. Без какой-то конкретики о постановке задачи. Абстрактно. Я вам указал на то, что это — ошибка и что тему «валидация email регулярным выражением» было бы правильно пометить в главу «Какие задачи не решаются регулярными выражениями».
Соглашусь. В конечном итоге Вы все равно правы.
Еще раз спасибо за дополнение. :)

Можно же .+@.+ =)

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

Если речь идет о валидации — условно можно.
С регуляркой из вашей статьи мы можем ошибиться с проверкой и отсечь верный email. Не особо страшно, тем более, что этот адрес будет достаточно экзотический.
С этой регуляркой мы почти все неверные адреса считаем верными. На мой взгляд такой подход — хуже.

Ну а если речь идет о поиске в тексте (как в вашей статье) — эта регулярка совсем не годится.

Наверно мы тогда о разных вещах говорили. Спасибо за дополнение.

Каждый раз глядя на своё программное решение с регулярными выражениями для разбора строк, чувствую, что единственное полезное выражение это «что-то (\d+)» и ничего другого лучше не писать.

Очень сложно поддерживать регулярные выражения в программе, всегда в первоначальный «простой» вариант вносятся изменения и усовершенствования. В итоге получается мини-монстр.
Как ящик пандоры — такие надежды всегда, а получается не совсем то.

На мой взгляд сама история появления регулярных выражений определяет их пределы использования. Они же родились в научной среде как некое теоретическое изыскание вылившееся в такой вот язык (утрирую конечно) и на практике оно впервые появилось в текстовом редакторе, чтобы можно было делать более сложные текстовые замены. И это стихия регулярных выражений.
Ты сделал замену регулярным выражением и сразу оценил результат, если он тебя устроил то регулярное выражение может кануть в забытие, т.к. оно выполнило свою роль. Это действительно бывает полезно.
В одной старой шутке говорится: если у вас есть проблема, и вы собираетесь решать ее с использованием регулярных выражений, то у вас есть две проблемы.
Какая же это шутка?
НЛО прилетело и опубликовало эту надпись здесь
Вообще я имел ввиду, что это нифига не шутка, а суровая правда жизни, а вовсе не просил рассказать мне эту шутку :)
Мне кажется, что главное все делать аккуратно.
Если приходится использоваться регулярку, ее стоит выносить в переменную с человеко-понятным названием. Желательно еще где-то рядом (в комментарии или документации) иметь пример текста, для которого регулярка должно работать верно.
И тогда жить станет чуточку проще, особенно тем, кто будет работать с кодом после.
НЛО прилетело и опубликовало эту надпись здесь
Определить, используя регулярные выражения?
Выглядит как эта задача.
www.hackerrank.com/challenges/ctci-balanced-brackets/problem
Регулярные выражения там может и применимы, но решается проблема насколько я помню через хешмап.
Задачу можно решить через инкремент/декремент целого числа, если на выходе не равно нулю, то скобки несбалансированы. Случаи, когда закрывающая идёт раньше открывающей, обрабатывается условием, что декрементировать 0 нельзя.
В случае одного вида скобок — да это будет супер элегантным решением.
Если несколько видов скобок, то по вашему алгоритму пройдет конструкция ( [ ) ], хотя она несбалансированая.
Если видов скобок несколько, то, естественно, алгоритм не сработает.

Но в комментарии стояла задача найти
все фигурные скобки в тексте
, т.е. только '{' и '}'.

Для разных видов скобок будет полезно применить стек, в который помещать открывающие скобки. При закрытии соответствующей скобки вынимать ее из стека. Выдавать ошибку, если закрывается не та скобка, которая верхняя в стеке.

НЛО прилетело и опубликовало эту надпись здесь
Это не очень удачное направление. Регулярные выражения (если не рассматривать некоторые расширения) непригодны для нормальной обработки рекурсивно вложенных структур.
Если с ходу сложно вспомнить регулярки (а я всегда перед их использованием гуглю), то на собеседовании нужно было переключиться на другой способ решения и попробовать его. Важен не только конечный решенный вариант, но поведение при сложностях с задачей.
НЛО прилетело и опубликовало эту надпись здесь
Да и не новичкам, я вам скажу. Стыдно признаться, но я никак не могу освоить эту технику. ;-) Хотя такие потребности возникают время от времени

Задачи со скобками как правило решаются с помощью стека же

Все дальнейшие примеры предлагаю смотреть в https://regex101.com/.
Два аргумента за использование regexr.com
1. На теле по ошибке добавить p — попадёшь на вирусняк с редиректом
2. Не работает в FF с выключенным параметром dom.workers.enabled (как и приват в avito)
[password|пароль]

Неправильная регулярка. Квадратные скобки должны быть заменены на круглые.
>['password', 'пароль', 'passwпароль', 'рольпа', 'drowssap'].map(w => /[password|пароль]/.test(w));
Array [ true, true, true, true, true ]
Верно, спасибо! Исправлено.
1. Регулярные выражения надо знать.
2.
Some people, when confronted with a problem, think «I know, I'll use regular expressions.» Now they have two problems.

--Jamie Zawinsk
Некоторые люди во время решения некой проблемы думают: «Почему бы мне не использовать регулярные выражения?». После этого у них уже две проблемы…
Jamie Zawinski
Когда-то на хабре видел статью про билибиотеку, строющую регулярные выражения из вызовов вроде regexp=new RegExp().startsWith(«aaa»).oneOf(«bbb»,«ccc»).oneOrMore(digit).endsWith(endOfLine);
Но не могу теперь найти. Кто помнит, как она называлась?
Спасибо. Да, я писал, что буква “ё” не входит в диапазон [а-я].

C кириллицей указанный диапазон работает по-разному для разных кодировок. В юникоде, например, в этот диапазон не входит буква “ё”. Подробнее об этом тут.
НЛО прилетело и опубликовало эту надпись здесь
Да, это особенность JS:
The RegExp object keeps track of the lastIndex where a match occurred, so on subsequent matches it will start from the last used index, instead of 0.


Спасибо, интересный момент.

Обращение к таким регуляркам лучше делать через getter, в котором обнулять lastIndex перед выдачей. Таким образом они всегда будут "чистыми".

Конечно, если lastIndex не планируется использовать как-то еще. Его же не зря придумали. :)
Это забавно. :D
Для начала: спасибо за подробную статью, сохраню, чтобы выдавать интересующимся для ознакомления.

Позволю себе только немного уточнить (здесь, т.к. это как раз может повлиять на новичков, которые часто берут примеры сразу в работу):
Но если мы укажем регулярное выражение “/\d/”, то нам вернётся только первая цифра. Мы, конечно, можем использовать модификатор “i”...

Видимо модификатор: «g»?

Или задать “от” и “до”, указав вот так: “{N, M}”.

Которые также можно задавать по отдельности вида “{N,}” или “{,M}”. Тоже полезная функция.

И ещё я бы упомянул про пассивные группы "(?:test)", которые не попадают в результат позволяют ограничить его только искомыми «полезными» группами.

Ну и мне очень часто помогает вот этот файлик.
Спасибо. Про «g» исправил. Поспешил, видимо, когда писал.

Остальное — тоже полезное дополнение. Нарушать структуру повествования уже поздно, но тут они будут ждать своего внимательного читателя. :)

ololo@mail.ru — хозяину этого адреса сейчас икаеться, наверно. А статья годная, спасибо.

Да, стоило быть избирательнее. Вдруг человек этот email использует для бизнеса.
Исправил, спасибо!
Спасибо, как начинающему front-end`у — отличное пособие!
Рад, что статья оказалось полезной. :)
[http|https] и http[s] не эквиваленты. Наверное, Вы хотели написать (http|https).
Верно, спасибо! Исправлено.
На самом деле не первая моя ошибка подобного рода — не могу избавиться от мысли, что знак или "|" должен работать без захвата тоже, с символами "[" и "]". :(
Не уверен, что до конца понимаю, почему это не так…
Зарегистрируйтесь на Хабре, чтобы оставить комментарий