Регулярные выражения – это система обработки текста, основанная на специальной системе записи образцов. Проще говоря представляет программистам возможность легко обрабатывать и валидировать строки. Представляет имплементацию принципа DRY (Don’t Repeat Yourself), почти во всех поддерживаемых языках паттерн регулярных выражений не будет изменятся от слова совсем. Код написанный на backend и frontend приложениях будет идентичным, тем самым позволяя экономить время командам на реализацию одинаковых фич. Также стоит акцентировать внимание на том, что данный модуль идеально подходит для работы с большими строками или сложными строками т.к. даёт возможность решать задачи связанные с ними просто и быстро. Бывает за чашечкой чая на кухне или в команде вы можете услышать, что регулярные выражения довольно сложные в изучение, написание и чтение и вообще их придумали ужасные люди ????. Но так ли это? Давайте разбираться

Примечание:

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

Как это выглядит

Далее представлены примеры на 6-х языках программирования определения российского номера телефона.

Паттерн

^(?:8|\+7)[0-9]{10}$

C#

new Regex(“^(?:8|\+7)[0-9]{10}$”).Match(“testdata”)

PHP

preg_match(“/^(?:8|\+7)[0-9]{10}$/”, “testdata”, match[])

Python

re.match(r’^(?:8|\+7)[0-9]{10}$’,’testdata’)

JS

/^(?:8|\+7)[0-9]{10}$/.exec(“testdata”)

Java

“testdata”.matches(“^(?:8|\+7)[0-9]{10}$”)

Dart

RegExp(r"^(?:8|\+7)[0-9]{10}$").allMatches(“testdata”)

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

История появления

Впервые регулярные выражения возникли в научных работах по теории автоматов и теории формальных языков в середине 1950-х. Стефан Коул Клин признан человеком, который впервые ввёл понятие Регулярных Выражений.

Принципы и идеи, заложенные в его работах, были практически реализованы Кеном Томпсоном и с его лёгкой руки проникли в язык Perl.

По определению, Регулярные Выражения – это модуль вашего языка программирования, который используются для поиска и обработки текста.

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

Какие языки программирования поддерживают их?

Список довольно обширный вот лишь несколько из них:

Языки программирования поддерживающие regex
  • C

  • C#

  • C++

  • Cobol

  • Delphi

  • F#

  • Go

  • Groovy

  • Haskell

  • Java

  • JavaScript

  • Julia

  • Kotlin

  • MATLAB

  • Objective-C

  • PHP

  • Perl

  • Python

  • R

  • Ruby

  • Rust

  • Scala

  • Swift

  • Visual Basic

  • Visual Basic .NET

Возможности

  • Сопоставление входных данных по шаблону.

  • Поиск и изменение входных данных по шаблону.

  • Возвращение первого или всех результатов из входной строки.

  • Возвращение вместе с результатом общего поиска, именованные и не только подстроки при поиске. 

  • Замена символов, слов, фраз в входной строке после прохода.

  • И самое главное, пиши один раз и используй везде.

Где пригодится?

  • Поиск и замена кода по паттерну в IDE (VS Code, Rider, CLion, VS)

  • Валидация строк на соответствие шаблону (file extension).

  • Валидация полей на фронте (e-mail, phone number and other).

  • Валидация request и response данных.

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

Базовый синтаксис

  • ^ – начало строки  (означает, что входная строка должна начинаться с последующего символа после этого. Не подходит если вы не знаете первый символ входной строки)

  • $ – окончания строки  (означает что все условия до этого символа буду являться конечным результатом входной строки и после них ничего дальше нет. Не подходит если вы хотите вернуть несколько результатов из входной строки)

  • * – означает что предыдущее условие до данного символа, может встречаться один или несколько раз или вовсе не будет (соответственно может повторятся)

  • + – означает что предыдущее условие до данного символа должно встречаться один и более раз (соответственно, может повторятся)

  • [a-z] – перечисление допустимого символа в входной строке, то есть может быть любой буквой из латыни в нижнем регистре (a or b or c … or x or y or z)

  • [0-9] – перечисление допустимого символа в входной строке, то есть может быть любой буквой из латыни в нижнем регистре (1 or 2 or 3 … or 7 or 8 or 9)

  • . – один любой символ

  • \ – экранирование любого спец. символа (ПРИМЕР)

  • | – операция OR (означает, что должно выполнится условие слева или условия справа от этой операнды)

Упрощение синтаксиса

  • \d ≡ [0-9] – любой символ от 0 до 9

  • \D ≡ [^0-9] – любой символ кроме чисел

  • \w ≡ [a-zA-Z0-9_] – любой символ латыни, все числа и _

  • \W ≡ [^a-zA-Z0-9_] – любой символ кроме латинских символов, чисел и _

  • \s ≡ [ ] – исключительно пробел

  • \S ≡ [^ ] – любой символ, кроме пробела

Разбор базового синтаксиса

Регулярное выражение

Позитивный результат

Негативный результат

(Ч|ч)асы

“Часы”, “часы”

“39”, “Уаз”, “Час”, “чсы”, “асы”

(Ч|ч)?асы

“Часы”, “часы”, “асы”

“39”, “Уаз”, “Час”, “чсы”

.асы

“Часы”, “уасы”, “#асы”, “Zасы”, “4асы”

“39”, “Уаз”, “Час”, “чсы”, “асы”

[0-9]+

“62”, “1”, “5123”, “632”

“abs”

a+b

“ab”, “aab”, “aaaaaaab”

“abs”, “b”, “cb” 

[0-9]*

“62”, “1”, “5123”, “632”

“abs”

a*b

“ab”, “aab”, “aaaaaaab”, “b”

“abs”

\+7

“+7”

“+1”, “++7”, “-7”

^\+7\d{10}

“+79991112233”, “+712345678900”

“+712345678”

^\+7\d{10}$

“+79991112233” 

“+712345678900”, “+712345678”

Длина условий

Кроме валидации значений в строке мы также можем указывать сколько символов должно проходить одно и тоже условие. Есть всего три возможности работать длиной условий:

  • {3} – обязательное кол-во символов для условия 

  • {3,5} – мин. и макс. кол-во символов для условия

  • {3,} – обязательное мин. кол-во и неограниченное макс. кол-во

Регулярное выражение

Позитивный результат

Негативный результат

[0-9] {3}

“632”, “777”, “891”

“39”, “1”, “5123”, “abs”

[0-9] {3,5}

“632”, “12345”, “5123”

“39”, “7”, “125123”, “abs”

[0-9] {3,}

“632”, “123456”, “5123”

“39”, “0”, “abs”

Примечание: Условие “[0-9]” можно заменить на сокращение “\d”

Работа с группами (Advanced)

Дальше будет немного сложно, готовьтесь.

  • () – создание анонимной группы  (создание подстроки и выделение на неё памяти)

  • (?‘nameGroup’) - (?<nameGroup>) – создание именованной строки

  • (\k<nameGroup>) – служит для избавления паттерна от дубликат кода, то-есть если у вас есть именованная группа “nameGroup” с каким-то условием, вы можете не писать вторую группу в паттерне, а просто использовать данную директиву регулярных выражением указывая лишь название группы, которая была описана до. Тем самым, условие будет повторятся и вам не нужно описывать его заново.

  • (?:) – выделение в логические скобки условия, без именование и создания подстроки

  • (<=) – Исключает условия внутри скобок и не включает его в выборку.

  • (?!) – Проверяет условия внутри скобок и не включает его в выборку.

Реальный пример из жизни

Однажды по работе нужно было парсить данные с QR кода, которые печатались на чеках при покупке/возврате разных товаров, услуг и т.д. Первая версия парсера была написана на бекенд части (C#). Кодовая база парсера была объёмом в ~150 строк кода, она не учитывала некоторые особенности разных фискальных регистраторов (устройства, которые печатают чеки и отправляют данные в ФНС). Для изменения данной функции требовалось внимательно смотреть, проверять каждую строчку кода. Позже вариантов стало так много и появилась необходимость использовать её на фронте для валидации. Соответственно, было решено переписать её, используя регулярные выражения для упрощение парсера и возможности легкого и быстрого переноса его на другой язык программирования.

Цели: 

  1. Парсить входные значения для валидации по шаблону

  2. Брать необходимые поля дату и сумму покупки для дальнейшего использования в системе.

  3. Проверять что поле “n” равно всегда 1 (0 – возврат, 1 – покупка)

Входные данные:

t=20181125T142800&s=850.12&fn=8715000100011785&i=86841&fp=1440325305&n=1

Регулярное выражение на парсинг данных:

^t=(?<Date>[0-9-:T]+)&s=(?<Sum>[0-9]+(?:\.[0-9]{2})?)&fn=[0-9]+&i=[0-9]+&fp=[0-9]+&n=1$

Пример кода (C#):

private static (string date, string sum) parseQRCode(string data)
{
   var pattern = new Regex(@"^t=(?<Date>[0-9-:T]+)&s=(?<Sum>[0-9]+(?:\.[0-9]{2})?)&fn=[0-9]+&i=[0-9]+&fp=[0-9]+&n=1$", RegexOptions.ECMAScript);
   var matchResult = pattern.Match(data);
   if (!matchResult.Success)
       throw new ArgumentException("Invalid qrCode");
   var dateGroup = matchResult.Groups["Date"];
   if(!dateGroup.Success)
       throw new ArgumentException("Invalid qrCode, Date group not found");
   var sumGroup = matchResult.Groups["Sum"];
   if(!sumGroup.Success)
       throw new ArgumentException("Invalid qrCode, Sum group not found");

   return (dateGroup.Value, sumGroup.Value);
}

Пример кода на JS:

Это вариант сделан через Exception-ы, но можно сделать через return false или return null.

const parseQRCode = (data:string) : {date: string, sum: string} => {
  const pattern = new RegExp("^t=(?<Date>[0-9-:T]+)&s=(?<Sum>[0-9]+(?:\.[0-9]{2})?)&fn=[0-9]+&i=[0-9]+&fp=[0-9]+&n=1$");
  const matchResult = pattern.exec(data);
  if (!matchResult)
      throw "Invalid qrCode";
  const dateGroup = matchResult[1];
  if(!dateGroup)
      throw "Invalid qrCode, Date group not found";
  const sumGroup = matchResult[2];
  if(!sumGroup)
      throw "Invalid qrCode, Sum group not found";
  return {date: dateGroup, sum: sumGroup};
};

На выходе мы получаем получаем два значения:

  1. Date – поле обозначающее дату и время покупки (осталось только спарсить её и превратить в объект даты)

  2. Sum – сумма покупки

Теперь давайте разберём паттерн поподробнее:

  1. ^ – обозначающая начало строки

  2. t=(?<Date>[0-9-:T]+) – обязательные символы  t=(далее любые символы (от 0 до 9 или - или : или T) в одном или более экземпляре)

  3. &s=(?<Sum>[0-9]+(?:\.[0-9]{2})?) – обязательные символы 

    1. &s= – обязательная последовательность символов & и s и =

    2. [0-9]+(символы от 0 до 9 одном или более экземпляре)

    3. (?:\.[0-9]{2})?

  4. $ – обозначающая конец строки

  5. &fn=[0-9]+ – обязательные символы &fn= и далее [0-9]+ -> (любое число от 0 до 9 в одном или более экземпляре)

  6. &i=[0-9]+ – обязательные символы &i= и далее [0-9]+ -> (любое число от 0 до 9 в одном или более экземпляре)

  7. &fp=[0-9]+ – обязательные символы &fp= и далее [0-9]+ -> (любое число от 0 до 9 в одном или более экземпляре)

  8. &n=1 – обязательные символы &n=1

Проблема работы с не латынью

Когда вам необходимо работать со всем алфавитом из латыни, достаточно просто написать [a-zA-Z]. Многие подумают что при работе с кириллицей хватает написать [а-яА-Я]. Вроде всё логично и всё хорошо, но в какой-то момент вы поймете, что у вас иногда она работает некорректно. Проблема заключается в том, что диапазон [а-я] не включает в себя букву “ё”, соответственно, вам необходимо изменить ваш паттерн с [а-яА-Я] на [а-яёА-ЯË], чтобы код учитывал специфичную букву в алфавите. Такая проблема есть не только в кириллице, также эта проблема актуальна для греческого, турецкого и ряда других языков. Будьте внимательны при написание паттерна, который должен использовать эти языки.

Флаги regex в JS

  • global (g) - не прекращает поиск после нахождения первого соответствия.

  • multi line (m) - ищет по строке включая перенос строки (^ начало строки, $ конец строки).

  • insensitive (i) - производить поиск вне зависимости от регистра (a ≡ A)

  • sticky (y) - поиск возвращает, кроме совпадения индекс с начала совпадения подвыборки (не поддерживается в IE)

  • unicode (u) - поиск включает unicode символы (не поддерживается в IE)

  • single line (s) - в этом режиме символ “.” включает в себя также перенос на новую строку (поддерживается в Chrome, Opera, Safari)

Дополнительные настройки regex в C#

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

  • None - выставляется по дефолту.

  • IgnoreCase (\i) - проверяет без учёта регистра.

  • Multiline (\m) - работа со строкой где есть переносы \n.

  • ExplicitCapture (\n) - добавляет в результат только именованные группы.

  • Compiled (будет полезен лишь в static варианте, ускоряет регулярку, замедляет компиляцию).

  • Singleline (знак “.” будет обозначать любой символ кроме \n и игнорирует его при поиске)

  • IgnorePatternWhitespace (\x) . (вырезает все пробелы, исключения в конструкциях[],{})

  • RightToLeft - поиск справа налево.

  • ECMAScript (JS like версия, но стиль группировки как в .NET).

  • CultureInvariant (сравнивает игнорирую раскладку клавиатуры).

Хорошие практики и советы по оптимизации

  1. Чем меньше группировок, тем быстрее скорость выполнения. Cтарайтесь их избегать, если они вам не нужны.

  2. Используя сокращения (\d, \w и другие), будьте уверены что они полностью соответствуют вашим условиям поиска.

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

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

  5. Старайтесь уменьшить количество экранирования (\), данный функционал замедляет скорость выполнения во многих языках программирования.

  6. У регулярных выражений есть поддержка utf кода символов. В некоторых моменты это позволит улучшить производительность, но уменьшит читаемость. Если решитесь их использовать, будьте уверены, что команда одобрит ваше решение и оно того стоит.

Заключение

Регулярные выражения лишь хотят казаться сложными, но на деле возможности которые они предоставляют дают массу возможностей и позволяют упростить и ускорить работу всем от Junior-а до Senior/Lead-a. Пожалуйста, если у вас будут вопросы милости прошу в комментарии, где мы сможем с вами подискутировать.

P.S. Программируйте это всё ещё классно)

P.P.S. Привет всем кто пришёл сюда с mergeconf

P.P.P.S. Спасибо Serge78rus за небольшое исправление по описанию операции +.

Ссылки

Замеры на разных языках

→ Онлайн regex-помощник со словарём всех доступных команд и поддержкой нескольких языков программирования.

Комментарии (32)


  1. mrBarabas
    20.11.2021 12:50
    +9

    Символ латыни - это примерно как цифры математики, лучше или латинский алфавит или латиница, кроме этого, \s - это не только пробел, а все пробельные сущности и их несколько. Время от времени приходиться использовать сложные регулярки (если что, я не программист) для поисков в текстах, html, коде и т.п. поэтому пришлось разобраться с этим, но помню время, когда это все выглядело как китайская грамота)). А еще есть онлайн сервисы, которые помогают сэкономить время типа regex101.com, может кому-то ссылка пригодится


    1. Sineni Автор
      20.11.2021 15:38

      Спасибо за подробный разбор. regex101.com уже был указан в разделе "Ссылки".


      1. QtRoS
        20.11.2021 15:46
        +6

        Вот это серьезная неточность:

        • \s ≡ [ ] – исключительно пробел

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


  1. MaxiNeal
    20.11.2021 13:55
    +4

    Вопрос по пятому совету по оптимизации: каким образом экранирование может влиять на скорость выполнения?


    1. Sineni Автор
      20.11.2021 15:40
      -4

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


      1. eandr_67
        20.11.2021 18:31
        +5

        При добавлении лишнего экранирования будет — на наносекунды — замедлена компиляция регулярного выражения в процессе создания объекта Regex. Но время обработки анализируемой строки методами Regex никак не изменится.


  1. OlgaPy
    20.11.2021 14:51
    +1

    Отлично! Я бы ещё в советы добавила "Именуйте группы, пожалуйста". Это очень упрощает дальнейший разбор. Самим же потом вспоминать "а что я тут имел ввиду?". Особенно когда регулярка выглядит как забор.


  1. h1pp0
    20.11.2021 15:07
    +3

    Регулярки отлично подходят для единоразовых скриптов, но в production-ready коде что-то сложнее пяти символов является потенциальной проблемой. Их сложно читать, в них сложно искать ошибки, они могут интерпретироваться немного по-разному, у них разная поддержка юникода.

    Если задача хорошо решается без них, то лучше их не использовать. В ином случае -- обязательно покрывать тестами.

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

    (\+*)((0[ -]+)*|(91 )*)(\d{12}+|\d{10}+))|\d{5}([- ]*)\d{6}

    А регулярка для email даже имеет свой сайт.


    1. NN1
      20.11.2021 16:17
      +1

      Для этих целей можно использовать построитель регулярных выражений с человеческим видом, например https://github.com/bcwood/FluentRegex


    1. Survtur
      20.11.2021 16:19
      +3

      Я в python использую флаг re.VERBOSE, что позволяет писать регулярку в несколько строк, добавлять комменты и пр.

      # Stupid demo. Same as re.compile(r"\d+\.\d*")
      a = re.compile(r"""\d +  # the integral part
                         \.    # the decimal point
                         \d *  # some fractional digits""", re.VERBOSE)


  1. Alberto42
    20.11.2021 15:11
    +2

    исправьте, пожалуйста, ошибку:

    для выражения [0-9]* "abs" тоже позитивный результат


  1. dzhiharev
    20.11.2021 15:11
    +2

    У вас ошибка в примерах в разделе «Разбор базового синтаксиса».
    Для регулярного выражения \+7 значение “++7” будет позитивным, а не негативным результатом.


    1. dzhiharev
      20.11.2021 15:19
      +1

      И в примерах с длинами условий тоже ошибки:
      для выражения [0-9] {3} строка “5123” и для выражения [0-9] {3,5} строка “125123” дадут позитивный результат


    1. Sineni Автор
      20.11.2021 15:36
      -2

      Данные примеры больше для понимания разработчиков уровня Junior, понятно что для полного правильного кейса стоит использовать ^\+7$. При таком паттерне мой пример будет корректный, но всё таки это больше статья для начинающих поэтому не стоит усложнять примеры)


      1. dzhiharev
        20.11.2021 16:49

        У вас в примерах есть значения как с явным указанием начала строки, так и без него. Значит вы хотели продемонстрировать разницу. Делать это, приводя некорректные примеры очень плохо. Особенно для разработчиков уровня Junior. Это опытные разработчики поймут, что вы ошиблись, а новички зависнут в попытке понять почему должен получится такой результат. И хорошо еще, если они догадаются запустить код и проверить…


  1. justmara
    20.11.2021 16:14
    +4

    про greedy/lazy ни слова? значит, скоро познакомитесь через новые седины

    и не забываем классиков:
    > Some people, when confronted with a problem, think "I know, I'll use regular expressions." Now they have two problems.


  1. sergeymolchanovsky
    20.11.2021 17:44

    На Dart я бы двойные кавычки на одинарные заменил - есть линт https://dart-lang.github.io/linter/lints/prefer_single_quotes.html, рекомендующий использовать только одинарные кавычки (просто для удобочитаемости)


  1. KvanTTT
    20.11.2021 20:37
    +1

    А в чем смысл делать английский заголовок для русской статьи?


  1. KvanTTT
    20.11.2021 20:45
    +6

    t=20181125T142800&s=850.12&fn=8715000100011785&i=86841&fp=1440325305&n=1

    Это как раз неудачный пример для парсинга регулярками. А что вы будете делать, если порядок параметров изменится? Тут логичней было бы дробить строку сплитом сначала по &, потом по =, далее определять имя параметра и парсить его значение стандартными методами. Т.е. тут вообще можно без регулярок обойтись.


    Хорошие практики и советы по оптимизации

    Еще забыли: если можете обойтись без регулярок — не используйте их. А также имейте представление о контекстно-свободных парсерах.


    1. a1111exe
      21.11.2021 16:29

      Еще забыли: если можете обойтись без регулярок — не используйте их.

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


      1. saboteur_kiev
        23.11.2021 04:23
        +2

        Нельзя с этим согласиться.

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


        1. a1111exe
          23.11.2021 12:22

          Если какую-то проблему можно решить регуляркой, то почему бы это не сделать?

          Вы всегда легко можете посчитать сложность Вашей регулярки? Я не один раз сталкивался с случаями, когда решение на регулярке неприемлемо быстро убивало скорость при увеличении входной строки. Кроме того, убористая регулярка, конечно, тешит самолюбие, но уже чуть позже с большим трудом читается самим её автором. Может, где-то есть общество людей (отдельные гении не считаются), которые всегда легко читают регулярки и понимают их сложность, но я не удостоился с таким столкнуться.

          И если он где-то упрощает жизнь - то пользуйтесь.

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


          1. saboteur_kiev
            30.11.2021 01:47

            Вы всегда легко можете посчитать сложность Вашей регулярки?

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


    1. eandr_67
      21.11.2021 17:43
      +2

      Ещё большая неудачность примера в в том, что формат разбираемой строки — это передача параметров в GET-запросе и в одном из типов POST-запроса. Для разбора которых в языке, ориентированном на web (если не в «голом» C#, то в ASP.NET), ожидаешь увидеть готовый метод распаковки строки в ассоциативный массив или структуру.

      Например, в PHP это функция parse_str.


      1. Survtur
        21.11.2021 20:42
        +1

        Да. А в python это urllib.parse.parse_qs() и urllib.parse.parse_qsl()


  1. xslibris
    20.11.2021 21:12
    -3

    Паттерн ^(?:8|+7)[0-9]{10}$

    В ваш паттерн российских номеров совершенно случайно попал весь Казахстан.

    [0-6,8,9]{10} будет чуть точнее.


    1. ar2rsoft
      21.11.2021 03:50
      +1

      В российских номерах не бывает семёрок?


      1. xslibris
        21.11.2021 07:45
        +1

        Действительно - это было 'сильно' с моей стороны.

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

        В мобильных сетях нумерация 77\d{9} пока полностью за Казахстаном. Изначальный смысл комментария был в этом.


  1. saboteur_kiev
    20.11.2021 23:41

    Принципы и идеи, заложенные в его работах, были практически реализованы Кеном Томпсоном и с его лёгкой руки проникли в язык Perl.

    Насколько я знаю, Кен был тем, кто реализовал их в ed, grep и др.

    А в Perl они были впервые реализованы уже в самом языке, а не при помощи внешней библиотеки. И Гвидо реализовал гораздо больше, чем было в изначальных extended regexp.
    И уже после Perl появилась свободная библиотека PCRE, на базе которой регулярки появились в других языках.

    – означает что предыдущее условие до данного символа, может встречаться один или несколько раз или вовсе не будет (соответственно может повторятся)

    Какой-то странный перевод. Что такое "условие" неоднозначно. Было бы лучше пояснить правильную терминологию - что такое мета-символ, что такое якорь, что такое квантификатор. А тут, как в очень многих других "не очень" инструкциях, просто вываливают какое-то количество знаков, которое нужно заучить наизусть.

    Уж проще почитать справку на regex101


  1. DmitryKoterov
    21.11.2021 12:43
    +2

    Помню в середине 90-х, когда B-деревья были большими, мне потребовалось реализовать что-то типа сопоставления с образцом на Borland C++ 3.1 под DOS на 80286-м. Интернета еще не было не у всех не, я не знал, что «все уже украдено до нас», и поэтому по сути пришлось изобретать регулярные выражения (с упрощенным и извращенным синтаксисом, естественно). Через несколько лет интернет завезли, и я узнал о PCRE. И мне даже удалось ее скомпилировать в BC3.1! Правда, там было несколько десятков тысяч строк кода, и размер получавшегося exe-шника не лез ни в какие ворота (да и компилировалось оно добрых минут 20 на 80286, постоянно упираясь в память), так что дальше забавного эксперимента это никуда не пошло.


  1. rpsv
    22.11.2021 15:09
    +1

    Немного иронично что в статье "Regex for lazy developers" нет никакой информации про lazy выражения: https://regex101.com/r/id4r4i/1

    Достатошно полезная штука, особенно в HTML.


  1. boojum
    25.11.2021 19:59

    \w ≡ [a-zA-Z0-9_] – любой символ латыни, все числа и _

    В общем случае это неверно.

    \w - это Символ «слова». В зависимости от реализации это может быть не только латиница. В python3 например, в эту маску попадут и символы национальных алфавитов.