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

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

Это конечно 1001 статья про регулярки. Ну ок, лайк, написано неплохо. Про себя замечу, что когда-то я боялась регулярных выражений, но в какой-то момент сделала усилие над собой, и после этого прям затащилась от них, и теперь "вижу" их применение везде (где может и не надо). Вплоть до того, что решаю алгоритмические задачи через регулярные выражения. Например преобразую массив в строку, проворачиваю нужные операции на базе регулярных выражений и возвращаю обратно массив. (Если конечно производительность не критична).

Спасибо за отзыв. Я тоже не любил регулярки, но когда в них разобрался, решил простым языком объяснить их и помочь людям в них разобраться.

и теперь "вижу" их применение везде (где может и не надо)

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

Some people, when confronted with a problem, think «I know, I'll use regular expressions.» Now they have two problems.
--Jamie Zawinski

С учётом lookahead и lookbehind они вроде бы тьюринг-полные. Так что в теории с помощью них можно решить любую задачу, но не следует. Попробуйте теперь кс-грамматики и генераторы парсеров - с помощью них можно тоже не только языки парсить.

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


И ваш код проходит ревью? Как вы, собственно, объясняете коллегам своё алгоритмическое решение?
Синтаксис (правила написания регулярок) не привязан к какому-то отдельному языку программирования. Поэтому, изучив регулярные выражения, вы сможете пользоваться ими где захотите.
Это не совсем так, существуют разные диалекты регулярных выражений. В том же sed, например, чтобы + воспринимался как квантификатор, его необходимо предварять символом \. И этим различия не заканчиваются, я привел это только как пример.

Спасибо за информацию. Теперь буду знать

> Информации о регулярках много, они разбросаны по разным сайтам

И сведены воедино в книге Фридла Mastering Regular Expressions.

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

Чем не устроили другие статьи на Хабре?

Интересно, что `/s{3}/g` не сопоставляется с последними `sss`: s ss sss ssss.
Так и должно быть?
Да, потому что жадно. Чтобы найти последние sss в каждой последовательности, понадобится negative lookahead: /s{3}(?!s)/g

У Васи была проблема с сортировкой электронной почты. Он решил использовать регулярные выражения. Теперь у него 2 проблемы.) Не в упрек регуляркам, просто когда-то улыбнуло).

куча статей про то, как писать регулярки, но ни одной про то, как их потом читать ))

Несколько лет, как для написания и чтения использую сайт https://regex101.com/(есть похожие, мне просто этот понравился). Там и шпаргалка есть и описание введённого выражения и сразу протестировать можно. Но мои выражения были довольно простыми, возможно для сложных случаев не подойдёт.

Отлично подходит и для сложных. Тоже этот сайт использую.

Все верно, ведь этот вопрос напрямую проистекает из того, как их написать.

Для этого мы можем написать следующее [A-Z,a-z] . Что же это значит? Это значит, что мы указали, что мы хотим выбрать все символы в диапазоне от A до Z (это мы выбираем все заглавные буквы) и, затем, через запятую, мы говорим о том, что хотим выбрать все символы от a до z

Запятая тут не нужна, и даже лишняя. Запятая выберет в тексте собственно запятые, кроме букв, то есть "text,text" будет выбран полностью. Писать надо слитно [A-Za-z]. А ещё есть аналогичный для кириллицы [А-Яа-я], но он не захватывает букву ё, и её надо отдельно указывать: [А-Яа-яЁё].

А ещё в статье не описан наверное самый сложный концепт регулярок, это lazy/greedy квантификаторы. При этом описаны достаточно экзотические lookahead/lookbehind.

Согласен, виноват, учту свои ошибки. Спасибо

А почему нельзя писать `[A-z]`? Оно же вроде тоже самое, что и `[A-Za-z]`

Можно и так :)

Потому что [A-z] эквивалентно [A-Z[\\\]^_`a-z]

Спасибо, буду знать

Возможно, но это просто чисто субъективный аспект, кому как удобнее.

\w означает не букву, а word character — буквы, цифры и подчеркивание.

Ещё один крутой инструмент для написания, тестирования и разработки регулярных выражений: https://regexr.com/

Пользуюсь только им

Существует много сайтов где можно проверить регулярки, а существуют ли сайты с заданиями на эти самые регулярки и проверкой результата? Обучение бы пошло в разы эффективнее

Конкретных сайтов нет. Но можно найти некоторые задания. Например, вот ссылка: http://old.code.mu/tasks/javascript/regular/rabota-s-regulyarnymi-vyrazeniyami-v-javascript-glava-1.html

Там несколько частей, можете просто перейти на след страницу

Много опечаток, а различные примеры в тексте нужно как-то выделять среди обычного текста, t. в конце строки может сбить с толку.

Стоит добавить хотя бы пару конкретных примеров из практики.

И ещё, скрины тяжело читать на мобильной версии, можно сделать скрины менее вытянутыми горизонтально.

Хорошо, все это я учту при написании последующих статей. Спасибо за отзыв

и ни слова про ReDoS.

https://en.wikipedia.org/wiki/ReDoS#Evil_regexes

https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS

Может так получится что ваша простая регулярка для проверки того же email'а в форме валидации веб приложения, не завершится в обозримом будущем. подвешивая ваше приложение.

на regex101 удобно показывает количество шагов для вычисления регулярки. И есть дебаг вычисления.

20 лет пишу регулярки (т.к поддерживаю несколько проектов на perl, хотя основной язык python) и могу дать один совет, который облегчит восприятие и логику регулярок: не пользутесь фичами с заглядывания вперед/назад. Да, призыв не использовать функционал звучит странно. Но столько людей спотыкаются в них и регулярно обращаются к документации чтобы освежить в памяти именно этот момент.
Чем же их заменить? почти все случаи заменяются на такие приемы:
1) захватить в (блаблаблла) то, что должно присутствовать в тексте и не должно быть изменено, после чего этот же фрагмент вставить в результат как $1 ($2 и тд)
2) использовать [^чего_не_должно_быть]
все это читается на раз-два, в отличие от всяких (?<=Y)X

Согласен. У самого такое было. Про них я написал для того, чтобы было представление о них. Спасибо за совет

Эквивалентом (?<!foo)(bar) без использования lookbehind будет (?:^|[^o]|^o|[^o]o|^oo|[^f]oo)(bar).
Читается на раз-два?!?

Я же написал "почти все случаи". И перед тем как нажать на сабмит, подумал "но все равно отпишется человек, который найдёт контр пример". Очевидно, что раз фича есть, значит скорее всего от неё будет польза. Мой совет основан на опыте. Причём не только личном. Это и личные обращения" помоги составить регулярку, влом доки читать" и код ревью. Я лишь советую как облегчить себе жизнь. 99% практических регулярок оно покрывает

Хорошо, приведите хоть один пример, где замена negative lookahead/-behind по вашему способу упрощает чтение выражения.

«но все равно отпишется человек, который найдёт контр пример»

Вы так говорите, как будто я какой-то каверзный редкий случай запостил, а не самый примитивный из возможных пример использования negative lookbehind.

Повторю: я дал совет исходя из своего и опыта коллег. Я и они решали практические задачи. Вот эти сотни практических задач подходят под мой принцип. Если у кого-то много регулярок с отрицаниями, которые надо исключить из поиска, тогда прошу прощения, мой совет не для вас. Но, повторюсь, в большинстве случаев он работает и позволяет не отвлекаться на чтение в доках постоянно забываемой фичи и обнаруживания, что у неё есть свой отдельный синтаксис для (не) жадности

Сотни практических задач, но ни одного конкретного примера? Всё понятно.

Хорошо, сегодня буду за компом, напишу. С мобилы не очень удобно регулярки писать

Приведу на perl, поскольку (внезапно) на нем лаконичнее. Самое простое, когда необходимо найти фрагмент, перед и/или после которого стоит определенный фрагмент:

$s = "This is a <b>test</b>!";
$s =~ m|<b>(.*?)</b>|;
print $1; # печатает test


Здесь, как я говорил, лучше не использовать сущность "найденный фрагмент" и заглядывания вперед/назад, а проще применить группировку ($1). Пример простой, а вот с заменой немногие, не имея опыта, догадатся сделать так:

# заменим "test" или "bug" на "code" только если впереди стоит фраза
# "this is a " или "that is a "
$s =~ s/(this|that) is a (test|bug)/$1 is a code/;
# или так
$s =~ s/(this is a|that is a) (test|bug)/$1 code/;
# добавим пробелы вокруг text в <любой tag>text</любой tag>
$s =~ s|(<[^>]+>)(.*?)(</[^>]+>)|$1 $2 $3|;

Если человек понимает больше чем час изучения регулярных выражений, во втором примере я ему еще и предложу использовать \1. За "более боевыми" примерами надо лезть в код проектов и находить такие пограниченые варианты, но мне кажется этого итак достаточно, чтобы понять о чем речь. Если кому-то мой вариант менее понятный чем заглядывания - ради бога, я не расстроюсь, что кому-то он не подходит.

Спасибо, но я просил
хоть один пример, где замена negative lookahead/-behind по вашему способу упрощает чтение выражения.

Прочитал название, удивился, зашел почитать статью. Увы, это не регулярки проще, это статья для начинающих...

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

Статьи на Хабре не помогли?

Как я и говорил в начале статьи, во время изучения регулярок информация была разбросана везде по частям. Вот я и решил в одну статью вписать основы, которые помогут новичкам лучше разобраться

Самая первая строка в поиске: habr.com/ru/post/545150 (Регулярные выражения (regexp) — основы)
Предельно наглядно для новичка. Настолько наглядно и в одном месте, что ваш материал — шаг назад. Что в ней не было так?

Хорошая, годная статья. Особенно для первой! Добро пожаловать на хабр.

Вот еще ресурсы для проверки регулярок.

Все они +- одинаковые, но тут уже, как говорится, на вкус и цвет фломастеры разные (красные не очень).

Спасибо большое за отзыв, рад, что статья понравилась. Да, кому какие сайты нравятся. И, как вы уже сказали, они действительно приблизительно одинаковые

Всё круто, как маленькая придирка - вместо примера с email вначале лучше взять что-нибудь попроще, на тему как правильно валидировать email адреса сломано немало копий, и по факту способа лучше, чем отправить туда письмо - до сих пор никто не придумал.

И так мы убьем двух зайцев - проверим, что мыло валидное и существует, и что оно пользователя

Спасибо за отзыв. Рад, что понравилась статья. Да, согласен с вами.

Осмелюсь предложить ещё regexper.com

Позволяет представлять регулярные выражения в графическом виде. Может быть кому-то пригодится для анализа регулярок, особенно если они написаны не вами и давно. Мне в свое время очень сильно помогло.

Правда, я не помню, все ли функции регулярок он поддерживает. Например, lookahead и lookbehind я не помню точно, так как не сталкивался с ними тогда.

Здравствуйте, может тогда подскажите мне, а то я никак справиться не могу :(
Есть у меня слова и словосочетания (огромное кол-во, порядка 70К). Их нужно удалить из текста в рамках тегов

****

если они там присутствуют. Я так понял нужно использовать знак | Но как…

Насколько я понял, нужно удалить слова, которые находятся между тегами? Ну тогда ситуация такая: допустим есть такая вещь: <p>Some text</p>. Получается, что если словосочетание находится между символами > и символом <, то его нужно удалить. Выбрать данное словосочетание можно с помощью ретроспективной и опережающей проверки, про которые я говорил в статье. Если же lookahead не поддерживается, то можно попробовать заменить его. Я просто не знаю подробностей вашего задания. Возможно я неправильно понял описанную вами проблему, но это первое, что мне пришло в голову

Почему бы не использовать полноценный парсер (у вас же что-то вроде HTML) или хотя бы лексер?

Коллега, спасибо за статью!

Обратите внимание, что регулярное выражение - это механизм, который определяет какие последовательности символов входят в язык, а какие - нет. Он изначально не привязан к тексту. Хотя текстовые строки и являются частным случаем строк, с которыми работает регулярка, но также она может быть задана для строк, состоящих из emoji, например, или бинарных символов.

Также коллеги выше правильно заметили, что синтаксис регулярных выражений может меняться в зависимости от имплементации.

Вы можете ознакомиться с курсом "теория автоматов" на edx, там хорошо рассказано про регулярные выражения, на мой взгляд. Кстати, для меня было большим откровением узнать, что конечные автоматы и регулярные выражения - это одно и то же, с точки зрения решаемой задачи.

Учту, спасибо вам большое!

Пожалуйста! Продолжайте писать!

Сразу дам ссылку на сайт, чтобы вы могли уже писать вместе со мной www.regextester.com

ошибка 503

Видимо у них проблемы на сервере

Я бы ещё про нюансы работы регулярок с многострочным текстом добавил и сделал акцент на регистрозависимость по умолчанию.

Спасибо за статью

Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.