Дисклеймер

Данная статья написана с уклоном на практическое применение регулярных выражений в проектах. Изначально написана для начинающих разработчиков в моей компании. Статья включает в себя примеры использования на JavaScript (TypeScript).

Введение

Регуля́рные выраже́ния (англ. regular expressions) — формальный язык, используемый в компьютерных программах, работающих с текстом, для поиска и осуществления манипуляций с подстроками в тексте, основанный на использовании метасимволов (символов-джокеров, англ. wildcard characters). Для поиска используется строка-образец (англ. pattern, по-русски её часто называют «шаблоном», «маской»), состоящая из символов и метасимволов и задающая правило поиска. Для манипуляций с текстом дополнительно задаётся строка замены, которая также может содержать в себе специальные символы.

Например, на вход приходит дата рождения в формате ДД.ММ.ГГГГ. Вам надо передать ее дальше, но уже в формате ГГГГ-ММ-ДД. Как это сделать с помощью простого поиска? Вы же не знаете заранее, какая именно дата будет.

Примеры использования регулярных выражений:

  1. Удалить все файлы, начинающиеся на test (чистим за собой тестовые данные)

  2. Найти все даты в тесте

  3. Удалить все ненужные строки из тестового файла (например: поток данных из b2b)

  4. Сопоставить переводы в репозитории с переводами из CMS (https://www.npmjs.com/package/check-i18n)

  5. Создать конвертер данных с валидацией входных данных в виде строки

  6. Валидация телефона, почты, ФИО

Работа с регулярными выражениями

Написание регулярных выражений

По своей сути, регулярные выражения являются языком разметки, аналогично HTML. В любом случае потребуется использование справочников при работе с ними (и постепенное запоминание ввиду опыта и частоты использования). Как показал опыт, наиболее полезным справочником оказался сайт https://developer.mozilla.org/ru/docs/Web/JavaScript/Guide/Regular_Expressions.

Статья в Википедии оказалась также полезной - https://ru.wikipedia.org/wiki/Регулярные_выражения - но стоит делать скидку на то, что Википедию могут редко или неверно редактировать любые люди и информация может быть не всегда достоверной (в то время как MDN является основным справочником для разработки frontend). 

Для фронтенд-разработчиков рекомендуется к прочтению - https://learn.javascript.ru/regexp-methods.

И да, фактически, единственным способом изучить регулярные выражения является практика работы со справочником. На первом этапе будет условно-достаточно прочитать статью на MDN.

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

Особенности написания RegExp в JS (TS)

Общее

При написании регулярных выражений в JS (TS) большого размера или сложности у разработчика чаще всего возникает необходимость повторения или переиспользования частей регулярного выражения в том же выражении. Логично будет работать с применением принципа DRY и создать переменную, в которую будет вынесен повторяющийся отрезок выражения. Также вынесение в отдельный отрезок будет способствовать улучшению читаемости и будущего редактирования.

Стоит обратить внимание на нюансы при работе с классом RegExp и встроенной в язык интерпретацией регулярных выражений посредством синтаксиса (оборачивание в слеш):

  • лучшей практикой при работе с регулярными выражениями из своего опыта считаю создание регулярных выражений через класс RegExp

  • нельзя нормально конкатенировать две сущности класса RegExp, т.к. во время создания RegExp задается практически неизменяемый паттерн в конструкторе

  • для конкатенация двух отдельных регулярных выражений необходимо заранее архитектурно проработать входящие данные в сущность RegExp (т.е. заранее работать со строкой)

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

    • при использовании кавычек внутри строки необходима изоляция значения внутри строки для символа кавычек (см. пример переменной QUOTES_REGEXP_STR)

    • строка "съест" обратный слеш при создании строки, необходимо дублирование знака обратного слеша для прокидывания в регулярное выражение

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

Пример использования на реальном проекте:

const QUOTES_REGEXP_STR: string = '('|"|`)';

const rawVar: string = [a-zA-Z\\-_%\\.1-9];

const keyStaticWithQoutes: string = (${QUOTES_REGEXP_STR}${rawVar}{1,120}${QUOTES_REGEXP_STR});

const dynamicKey: string = (${keyStaticWithQoutes}\\s?\\+\\s?${rawVar}{1,30});

const key: string = (${keyStaticWithQoutes}|${dynamicKey});

const html: string = ${key}\\s?\\|\\s?translate;

const tsInstant: string = \\.instant\\(${key}\\);

const tsStream: string = \\.stream\\(${key}\\);

const pattern: RegExp = new RegExp(${html}|${tsInstant}|${tsStream}, 'gm');

Возможные проблемы

"Запоминание" положения поиска при работе с классом RegExp с флагом g

При работе с регулярным выражением через класс RegExp с флагом g, используя методы .exec('') или .test('') происходит модификация свойства lastIndex. Сами же методы  .exec('') и .test('') начинают проверку с позиции lastIndex.

Больше информации тут - https://learn.javascript.ru/regexp-methods#regexp-exec-str

Валидация написанных выражений

Для работы с регулярными выражениями крайне удобно использовать онлайн сервисы:

Если есть необходимость абстрагирования от онлайна, то можно использовать встроенные возможности текстовых редакторов или IDE, например:

  • Notepad++ (установить Search Mode → Regular expression)

  • Поиск в IDE Jetbrains (например: Webstorm) с указанием использования регулярного выражения (справа строки поиска значок "[.*]")

FAQ

Почему регулярное выражение указано обернутым в символах слеша?

При  написании регулярных выражений в языках программирования есть различный синтаксис создания регулярных выражений как объекта. Например, в JS (TS) для создания объекта регулярного выражения можно использовать два способа: создание через конструктор класса ("new RegExp") или через синтаксис регулярного выражения через оборачивание прямыми слешами ("/выражение/"). Иногда данный синтаксис может встречаться в сопутствующих текстах. В данных случаях выражение без прямых слешей является синонимичным выражению без слешей.

Ссылки

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


  1. x4erem6a
    20.04.2023 06:13

    Чтобы строка не съедала обратные слеши можно использовать String.raw:

    const pattern = String.raw`\d+`


  1. x4erem6a
    20.04.2023 06:13

    Чтобы строка не съедала обратные слеши можно использовать String.raw:

    const pattern = String.raw`\d+`