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

Источник: «Regular expressions in JavaScript»
Регулярные выражения могут быть пугающими, но это не так! Узнайте все необходимое о регулярных выражениях и их использовании в JavaScript.

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

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

Необходимые требования

Чтобы извлечь максимальную пользу из этой статьи, необходимо лишь базовое понимание JavaScript; все концепции и примеры кода будут подробно объяснены.

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

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

Регулярные выражения, также известные как regex или regexp, представляют собой паттерн или шаблон для сопоставления строк. Эти шаблоны представляют собой последовательность символов, определяющих шаблон поиска, что позволяет разработчикам выполнять такие задачи, как проверка исходных данных, поиск определённого текста и замена частей строки.

Рассмотрим, как регулярные выражения могут помочь в решении этих задач, на примере извлечения адресов электронной почты из текста:

let text = "John's email is john@example.com and Jane's email is jane@example.com. You can contact them at these addresses.";
let words = text.split(" ");
let emails = [];

for (let i = 0; i < words.length; i++) {
if (words[i].includes("@")) {
emails.push(words[i]);
}
}

console.log(emails);

В приведённом выше коде используется цикл for с оператором if для извлечения слов с символом @ в массив под названием emails.

Посмотрим, как регулярные выражения могут решить эту проблему:

let text = "John's email is john@example.com and Jane's email is jane@example.com. You can contact them at these addresses.";
let emails = text.match(/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g);
console.log(emails);

Приведённый выше код решает ту же задачу, но с использованием regex-подхода и меньшим количеством строк кода. Оба решения должны возвращать один и тот же результат:

[ 'john@example.com', 'jane@example.com' ]

Примечание. Первый пример, без regex, некорректный. При разбиении строки на "слова" по пробелам, в адрес электронной почты попадёт лишняя точка, в конце — jane@example.com.

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

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

Создание шаблонов регулярных выражений в JavaScript

Существует два способа создания шаблонов регулярных выражений в JavaScript. Мы рассмотрим их в этом разделе.

Использование литеральной нотации

Самый простой способ создания шаблона регулярного выражения в JavaScript — это использование литеральной нотации. Вы можете создать шаблон, просто заключив его в слэши:

let pattern = /Hello/;

Приведённый выше код создаёт простой regex-шаблон, который будет соответствовать первому точному совпадению текста "Hello". Эта нотация используется, когда при написании кода известно, как будет выглядеть шаблон.

Примечание: Необязательно заключать шаблоны в одинарные или двойные кавычки; флаги можно добавлять после закрывающего слэша.

Использование нотации конструктора

В JavaScript имеется конструктор RegExp, который можно использовать для создания шаблонов regex. В качестве строкового аргумента в конструктор передаётся шаблон:

let pattern = new RegExp("\\w+", "g");

Приведённый выше код создаёт шаблон, соответствующий всем словам в заданном тексте. Первый строковый аргумент — это шаблон, а второй — флаг. Подробнее о флагах мы поговорим в следующих разделах.

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

function find(regexInput, text) {
const regexPattern = new RegExp(`${regexInput}`, "gi");
console.log(regexPattern.exec(text))
}

find("lazy", "The quick brown fox jumps over the lazy dog.") // returns "lazy"

Приведённый выше код создаёт функцию find, принимающую regexInput и text. Затем создаётся regexPattern, формирующий шаблон на основе regexInput, и, наконец, происходит вывод в консоль совпавшего текста с помощью метода exec для сгенерированного шаблона.

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

Тестирование шаблонов регулярных выражений в JavaScript

Существуют различные способы проверки шаблонов regex в JavaScript, в зависимости от того, какой результат вы хотите получить.

Метод match

Метод match возвращает массив с найденной строкой и null в случае отсутствия совпадения. Вы можете использовать метод match с шаблоном переданным в качестве параметра:

let pattern = /Hello/;
let input = "Hello, World!";
let result = input.match(pattern);
console.log(result);

Приведённый выше код создаёт шаблон, соответствующий первому вхождению текста "Hello", переменную с именем input и переменную result, которая будет выводиться в консоль. Результат должен выглядеть следующим образом:

[ 'Hello', index: 0, input: 'Hello, World!', groups: undefined ]

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

Метод test

Метод test ищет в строке шаблон регулярного выражения и возвращает true, если находит совпадение, и false, если не находит. Приведём пример:

let pattern = new RegExp("peaky", "gi");
let input = "Peaky Blinder is an interesting series";
let result = pattern.test(input);
console.log(result); // Выводит: true

Приведённый выше код создаёт шаблон для поиска слова "Peaky", предоставляет переменную input, использует метод test для проверки наличия совпадения и выводит результат на консоль.

Метод exec

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

Например, так вы можете протестировать шаблон с помощью метода exec:

const pattern = /\(\d{3}\) \d{3}-\d{4}/g;
const string = "My phone numbers are (123) 456-7890 and (555) 555-1212.";

let matches;
while (matches = pattern.exec(string)) {
console.log(matches);
}

В приведённом выше коде создаётся шаблон для поиска телефонных номеров, строка, содержащая два телефонных номера в формате, заданном шаблоном, и цикл while, перебирающий все совпадения, найденные методом exec, и выводящий каждое совпадение на консоль. Приведённый выше код возвращает следующее:

[
'(123) 456-7890',
index: 21,
input: 'My phone numbers are (123) 456-7890 and (555) 555-1212.',
groups: undefined
]
[
'(555) 555-1212',
index: 40,
input: 'My phone numbers are (123) 456-7890 and (555) 555-1212.',
groups: undefined
]

Метод search

Метод search обычно работает со всеми строками, но его можно использовать и для проверки шаблонов regex:

let text = "Hello, welcome to the world of hello!";
let pattern = /hello/i;
let index = text.search(pattern);
console.log(index); // Выводит: 0

Приведённый выше код создаёт шаблон, соответствующий слову "Hello", и использует флаг i для выполнения поиска без учёта регистра символов. Затем использует метод search для получения индекса первого совпадения в текстовой строке.

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

Синтаксис и структура регулярных выражений

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

Литеральные символы

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

Например, если дана строка Ben has grown bigger since I saw him last. Sally and Mary are big girls now too, то шаблон big будет соответствовать только первому big в строке, и не важно, что это часть одного слова. Также не имеет значения и второе big в строке, поскольку я использовал только литеральные символы.

Примечание: По умолчанию регулярные выражения чувствительны к регистру, поэтому big не то же самое, что Big, если только не использовать специальные символы для игнорирования разницы в регистре.

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

Специальные символы

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

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

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

Флаги

Флаги используются для изменения поведения сопоставления шаблонов в регулярных выражениях. Они могут изменять способ применения шаблона и по-разному влиять на процесс сопоставления.

К числу наиболее распространённых флагов относятся следующие:

Флаг g

Флаг g используется для выполнения глобального сопоставления шаблонов. При установке этого флага механизм регулярных выражений будет искать совпадения даже после того, как будет найдено первое совпадение. Без этого флага механизм регулярных выражений будет находить только первое совпадение во входной строке.

Например, регулярное выражение /hello/g будет соответствовать всем вхождениям строки "hello" в исходной строке. Без флага g регулярное выражение будет соответствовать только первому вхождению.

Флаг i

Флаг i используется для выполнения сопоставления шаблонов без учёта регистра. При установке этого флага механизм регулярных выражений будет сопоставлять символы в верхнем и нижнем регистре. Без этого флага механизм регулярных выражений будет сопоставлять только символы того же регистра, что и шаблон.

Например, регулярное выражение /hello/gi будет соответствовать как "hello", так и "Hello" в исходной строке.

Флаг m

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

Например, регулярное выражение /^hello/gm будет соответствовать всем вхождениям строки "hello" в начало строки в многострочной исходной строке.

Флаг s

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

Например, регулярное выражение /hello.world/s будет соответствовать строке "hello\nworld" в исходной строке.

Флаг u

Флаг u используется для выполнения сопоставления шаблонов Unicode. При установке этого флага механизм регулярных выражений будет использовать свойства символов Unicode и сопоставление регистров для сопоставления символов.

Например, регулярное выражение /[^\p{L}\p{N}]+/u будет соответствовать любой последовательности символов, не являющихся буквами или цифрами в Unicode строке.

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

Концепции регулярных выражений и метасимволы

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

Классы символов

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

Например, слова apologize и apologise являются правильными в зависимости от того, на английском языке какой страны написан данный текст, поэтому для соответствия одного или обоих слов в тексте можно использовать класс символов с квадратными скобками:

let pattern = new RegExp('apologi[sz]e', 'g');
let input = "apologize and apologise are both correct";
let result = input.match(pattern);
console.log(result); // Выводит: ['apologize', 'apologise']

Наборы символов также хорошо работают при проверке слов, в которых часто допускаются ошибки, таких как calendar и cemetery:

let pattern = new RegExp('calend[ea]r', 'g');
let input = "calendar or calender";
let result = input.match(pattern);
console.log(result); // Выводит: ['calender', 'calendar']

Приведённый выше код делает то же самое, что и предыдущий блок кода, но с часто ошибочно произносимым словом Calender.

Набор негативных символов

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

let pattern = new RegExp('[^vwy]et', 'g');
let input = "get, yet, bet, wet, let, vet";
let result = input.match(pattern);
console.log(result); // Выводит: ['get', 'bet', 'let']

Приведённый выше код будет соответствовать всем словам, оканчивающимся на "et", кроме тех, которые начинаются на "v", "w" или "y".

Диапазоны

Диапазон — это более короткий способ записи набора символов. Например, если необходимо подобрать все цифры, начинающиеся с любого числа от 2 до 6 и заканчивающиеся двойными нулями, это можно сделать с помощью диапазона:

let pattern = new RegExp('[2-6]00', 'g');
let input = "200, 700, 300, 100, 590, 400";
let result = input.match(pattern);
console.log(result); // Выводит: ['200', '300', '400']

Приведённый выше код использует дефис - для определения диапазона, проверяет его и выводит результат в консоль. То же самое можно сделать и для слов:

let pattern = new RegExp('[a-h]010290', 'g');
let input = "a010290, i010290, d010290, f010290, i010290, n010290, s010290";
let result = input.match(pattern);
console.log(result); // Выводит: ['a010290', 'd010290', 'f010290']

Приведённый выше код делает то же самое, что и предыдущий, но на этот раз со словами, которые начинаются с букв a-h и заканчиваются 010290.

Существует и другой способ записи диапазонов, который заключается в использовании коротких кодов для [a-z], [0-9] и их точных противоположностей. Например, можно написать функцию, которая извлекает из текста адреса электронной почты:

const pattern = /\w+@\w+\.\w+/g;
const text = "John's email is john@example.com and Jane's email is jane@example.com. You can contact them at these addresses.";
console.log(text.match(pattern)); // Выводит: ['john@example.com', 'jane@example.com']

Приведённый выше код создаёт шаблон, который сопоставляет электронные письма в тексте с помощью \w, являющегося сокращением для [A-Za-z0-9_].

Рассмотрим подробнее базовые сокращения (шорткоды) и их описания:

Для быстрого создания сложных шаблонов можно комбинировать один или несколько метасимволов. Например, шаблон \d{3}-\d{2}-\d{4} может быть использован для поиска номера социального страхования США в формате "323-45-6789".

В следующем разделе мы рассмотрим квантификаторы и то, как они работают.

Квантификаторы

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

Астериск/звёздочка (*)

Астериск (*) — один из наиболее распространённых квантификаторов, обозначающий ноль или более вхождений предшествующего символа, или группы. Например, регулярное выражение "a" будет соответствовать любой строке, содержащей ноль или более символов "a". Это означает, что оно будет соответствовать пустой строке и любой строке, полностью состоящей из символов "a":

const pattern = /a*/;
const text = "Our organization is committed to providing excellent customer service and fostering strong relationships with our clients.";
console.log(text.match(pattern)); Выводит: ['']

Плюс (+)

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

const pattern = /a+/g;
const text = "Our organization is committed to providing excellent customer service and fostering strong relationships with our clients.";
console.log(text.match(pattern)); // Выводит: ['a', 'a', 'a', 'a']

В приведённом выше коде будут найдены и возвращены все вхождения символа "a" в заданной строке.

Фигурные скобки ({})

Квантификатор фигурные скобки ({}) задаёт точное количество вхождений символа или группы символов. Например, регулярное выражение /a{2,4}/ будет соответствовать любой строке, содержащей от двух до четырёх символов "a". Это означает, что оно будет соответствовать строкам типа "aa", "aaa" или "aaaa", но не строкам, содержащим менее двух символов "a" или более четырёх:

const pattern = /a{2,4}/g;
const text = "Our orgaanization is committed to providing excellent customer service aaand fostering strong relaaaationships with our clients.";
console.log(text.match(pattern)); // Выводит: ['aa', 'aaa', 'aaaa']

Ленивые квантификаторы

Как было показано в предыдущем разделе, квантификаторы используются в регулярных выражениях для сопоставления нескольких вхождений шаблона. Например, квантификатор + соответствует одному или нескольким вхождениям шаблона, а квантификатор * — нулю или нескольким вхождениям шаблона. Квантификатор ? соответствует нулю или одному вхождению шаблона.

По умолчанию квантификаторы являются жадными, т.е. они соответствуют как можно большей части строки. Вы можете сделать квантификаторы "ленивыми", добавив к ним символ ? Ленивые квантификаторы могут быть полезны в тех случаях, когда необходимо найти соответствие шаблону, который встречается в строке несколько раз, но при этом нужно найти только первое его появление. Например, рассмотрим следующее регулярное выражение:

const string = 'the cat sat on the mat';
const regex = /the.+?on/;
const match = string.match(regex);
console.log(match); // Выводит: ['the cat sat on']

Приведённый выше код создаёт шаблон, который соответствует только строке от "the" до "on", исключая "mat", поскольку квантификатор .+? является ленивым и соответствует как можно меньшей части строки.

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

Повторение

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

Круглые скобки (())

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

const pattern = /(ab)+/g;
const text = "abb abcb ababab";
console.log(text.match(pattern)); // Выводит: ['ab', 'ab', 'ababab']

Точка (.)

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

Например, шаблон a.{?}b будет соответствовать любой строке, которая начинается с символа "a", затем следует от трёх до пяти любых символов и заканчивается символом "b":

const pattern = /a.{3,5}b/g;
const text = "abbabcb desbdd cescse ababab";
console.log(text.match(pattern)); // Выводит: ['abbabcb', 'ababab']

Пайп(|)

Другим метасимволом, часто используемым для повторения, является символ пайп (|), который представляет собой выбор между двумя шаблонами. Например, шаблон a(b|c)d будет соответствовать любой строке, начинающейся с буквы "a", за которой следует либо "b", либо "c", а заканчивается она буквой "d":

const pattern = /a(b|c)d/g;
const text = "abcd dde acd abd";
console.log(text.match(pattern)); // Выводит: ['acd', 'abd']

В следующем разделе мы рассмотрим, как экранировать метасимволы.

Экранирование

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

let pattern = new RegExp('\\w+\\+', 'g');
let input = "wee+, let, kit, iPhone8+, i010290, n010290, s010290";
let result = input.match(pattern);
console.log(result); // Выводит: ['wee+', 'iPhone8+']

Приведённый выше код создаёт шаблон, соответствующий словам, заканчивающимся символом +, экранируя специальный символ \+. Без дополнительного \ перед специальными символами механизм regex прочитает шаблон как /w++/, что является недопустимым.

Примечание: При использовании буквенной нотации можно задать шаблон типа let pattern = /\w+\+/g, и приведённый выше код будет работать нормально.

Якоря

С помощью якорей можно определить начало или конец строки, или слова в строке. Часто используемыми якорями являются ^ — начало строки и $ — конец строки.

Например, можно подобрать слово "The", находящееся в начале строки:

const pattern = /^The/;
const string = "The quick brown fox jumps over the lazy dog.";
console.log(string.match(pattern)); // Выводит: ["The"]

С помощью знака $ можно сделать обратное действие:

const pattern = /\.$/;
const string = "The quick brown fox jumps over the lazy dog.";
console.log(string.match(pattern)); // Выводит: ["."]

Приведённый выше код создаёт шаблон, соответствующий символу "." в конце заданной строки.

Границы слов

Границы слов служат для тех же целей, что и якоря, но соответствуют не одному символу, а слову. Это границы двум слов для специальных символов:

Например, можно найти все слова, начинающиеся со слова "bet":

const pattern = /\bbet/gi;
const text = "Betty's better bet was to buy the blue blouse.";
console.log(text.match(pattern)); // Выводит: ['Bet', 'bet', 'bet']

Приведённый выше код создаёт шаблон, возвращающий количество повторов букв "bet", с которых начинается слово в заданном предложении, независимо от регистра.

Кроме того, как и с якорями, можно поступить наоборот, добавив \b в конце слова:

const pattern = /sion\b/gi;
const text = "After much discussion, the team came to a consensus on the vision for the project.";
console.log(text.match(pattern)); // Выводит: ['sion', 'sion']

Приведённый выше код создаёт шаблон, возвращающий количество раз, когда слова в заданном предложении заканчиваются буквами "sion", независимо от регистра.

Альтернативы

Иногда требуется проверить строку, в которой допустимо только одно из нескольких слов. Например, в заданная строка должна соответствовать либо слову business, либо слову organization:

const pattern = /business|organization/gi;
const text = "Our organization is committed to providing excellent customer service and fostering strong relationships with our clients.";
console.log(text.match(pattern)); // Выводит: ['organization']

Приведённый выше код вернёт ['organization'] или ['business'] в зависимости от того, что содержится в заданной строке.

Группирование

Группирование используется, когда необходимо использовать альтернативы несколько раз в шаблоне. Например:

const pattern = /(quick|lazy) (brown|gray) (fox|dog)/;
const text = "The quick brown fox jumps over the lazy dog.";
console.log(text.match(pattern)); // Выводит: ["quick brown fox"]

Приведённый выше код создаёт шаблон, соответствующий фразам "quick brown fox" или "lazy gray dog" в заданной строке.

Захват групп

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

Например, следующий шаблон, (hello)+, будет соответствовать любой последовательности слов "hello" один или несколько раз. Однако если обернуть последовательность "hello" в захват группы ((hello)+), то можно захватить все совпадающее содержимое внутри группы. Система регулярных выражений будет искать и перехватывать всю последовательность, включая повторные вхождения слова "hello".

Рассмотрим пример использования захвата групп:

const date = '02/18/2023';
const regex = /(\d{2})\/(\d{2})\/(\d{4})/;
const newDate = date.replace(regex, '$3-$1-$2');
console.log(newDate); // Выводит: '2023-02-18'

Приведённый выше код использует захват групп для создания шаблона, который захватывает части строки месяц, день и год в отдельных группах. Затем, используя обратные ссылки, он ссылается на захваченные группы в заменяемой строке в формате $n, где n — номер группы. Наконец, для перестановки даты в нужный формат используются ссылки на третью, первую и вторую группы с помощью $3, $1 и $2.

Обратные ссылки рассмотрим в следующем разделе.

Обратные ссылки

Обратные ссылки — это мощная функция регулярных выражений, позволяющая ссылаться на захваченные группы внутри регулярного выражения. Как видно из предыдущего примера, для ссылки на захваченную группу я использовал обозначение $n, где n — номер группы.

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

const string = 'the the cat sat on the mat';
const regex = /\b(\w+)\b\s+\1/g;
const newString = string.replace(regex, '$1');
console.log(newString); // Выводит: 'the cat sat on mat.'

В приведённом выше коде создаётся шаблон, соответствующий любому дублирующемуся слову в строке. Шаблон использует границу слова \b, чтобы гарантировать, что он будет соответствовать только полным словам, захват группы (\w+), чтобы захватить слово, и обратную ссылку \1, чтобы ссылаться на захваченное слово. Затем с помощью метода replace все совпадение заменяется захваченным словом, что позволяет удалить дублирующее слово.

Рассмотрим именованные захваты групп в следующем разделе.

Именованные захваты групп

Именованные захваты групп — это разновидность захвата групп, позволяющая присваивать имена захваченным группам, что упрощает извлечение совпадающего текста. Именованные захваты групп обозначаются синтаксисом (?<name>...), где name — имя захватываемой группы. Приведём пример:

const string = 'John Doe';
const regex = /(?<first>\w+)\s(?<last>\w+)/;
const match = string.match(regex);
console.log(match.groups); // Выводит: { first: 'John', last: 'Doe' }

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

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

Утверждения опережение/lookahead и ретроспектива/lookbehind рассмотрим в следующем разделе.

Опережение/lookahead и ретроспектива/lookbehind

Опережение/lookahead и ретроспектива/lookbehind — это мощные возможности регулярных выражений, позволяющие сопоставлять шаблоны на основе того, что находится перед или после данного шаблона, не включая опережение/lookbehind или ретроспективу/lookahead в соответствие. Эти конструкции представлены утверждениями (?<=...) и (?<!...) опережение/lookbehind, а также утверждениями (?=...) и (?!...) ретроспектива/lookahead.

Утверждение опережение/lookahead соответствует шаблону только в том случае, если за ним следует другой шаблон. Например, необходимо найти любое слово, за которым следует слово "is". Вы можете использовать положительное утверждение опережение/lookahead поиска для соответствия любому слову, за которым сразу следует слово "is":

const string = 'The sky is blue';
const regex = /\w+(?=\sis)/g;
const matches = string.match(regex);
console.log(matches); // Выводит: ['sky']

Приведённый выше код создаёт шаблон, соответствующий любому слову, непосредственно следующему за словом "is", но не включающий слово "is" в соответствие.

Утверждение ретроспектива/lookbehind соответствует шаблону только в том случае, если ему предшествует другой шаблон. Например, если требуется подобрать любое слово, предшествующее слову "the", можно использовать положительное утверждение ретроспектива/lookbehind для подбора любого слова, следующего сразу за словом "the":

const string = 'The cat sat on the mat';
const regex = /(?<=the\s)\w+/gi;
const matches = string.match(regex);
console.log(matches); // Выводит: ['cat', 'mat']

Приведённый выше код создаёт шаблон, соответствующий любому слову, непосредственно следующему за словом "is", но не включающий в соответствие слово "is".

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

Сопоставление Unicode в регулярных выражениях

Unicode — это стандарт кодирования символов, позволяющий представлять символы различных языков и систем письма. В регулярных выражениях предусмотрен флаг /u для соответствия символу Unicode в шестнадцатеричном формате.

Символы Unicode можно использовать в классах символов, квантификаторах и других конструкциях регулярных выражений. Однако сопоставление символов Unicode может быть затруднено, поскольку некоторые символы Unicode представлены несколькими точками кода. Например, символ "é" может быть представлен как кодовой точкой \u00e9, так и комбинацией кодовых точек \u0065 и \u0301. Это может привести к неожиданным результатам при сопоставлении символов Unicode в регулярных выражениях.

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

const string = 'café';
const regex = /f\u00e9/u;
const match = string.match(regex);
console.log(match); // Выводит: ['fé']

Приведённый выше код создаёт шаблон, соответствующий символу "é" в формате Unicode, используя флаг /u для включения режима Unicode в регулярном выражении.

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

Общие примеры использования на практике

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

Валидация формы

Регулярные выражения могут быть использованы для проверки данных формы, таких как адреса электронной почты, номера телефонов и пароли. Приведём пример использования регулярных выражений для проверки адреса электронной почты:

function validateEmail(email) {
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailPattern.test(email);
}
console.log(validateEmail('user@example.com')); // true
console.log(validateEmail('invalid_email')); // false

Поиск и замена

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

const paragraph = 'The quick brown fox jumps over the lazy dog';
const newParagraph = paragraph.replace(/quick/g, 'slow');
console.log(newParagraph); // Выводит: 'The slow brown fox jumps over the lazy dog'

Парсинг данных

Регулярные выражения могут использоваться для извлечения определённых данных из строки. Например, с помощью регулярного выражения можно извлечь все URL-адреса из блока текста:

const text = 'Check out this site: https://www.example.com and also this one: https://www.another-example.com';
const urls = text.match(/https?:\/\/\S+/g);
console.log(urls); // Выводит: ['https://www.example.com', 'https://www.another-example.com']

Манипуляция строками

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

const string = 'Th1s !s 4n ex@mpl3.';
const newString = string.replace(/[^a-zA-Z0-9]/g, '');
console.log(newString); // Выводит: 'Th1s4nexmpl3'

Маршрутизация URL

Регулярные выражения могут использоваться для поиска и извлечения параметров из URL-адресов в веб-приложении. Например, можно использовать регулярное выражение для поиска и извлечения параметра ID из URL:

const url = '/users/123';
const id = url.match(/\/users\/(\d+)/)[1];
console.log(id); // Выводит: '123'

Это лишь несколько примеров того, как можно использовать регулярные выражения в JavaScript.

Заключение

Регулярные выражения — это мощный инструмент для работы с текстом в JavaScript. Благодаря возможности сопоставления, поиска и замены текста с использованием сложных шаблонов регулярные выражения необходимы любому разработчику. Вы изучили основы регулярных выражений, включая синтаксис, наборы символов и повторение, а также расширенные темы, такие как опережение, ленивые квантификаторы и поддержка Unicode.

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

Это была длинная статья! Большое спасибо за прочтение, и я надеюсь, что эта статья достигла своей цели — научить вас всему, что нужно знать, чтобы начать эффективно использовать регулярные выражения в своём коде.

Дополнительные материалы

Предыдущая Статья

В Вашем JS-приложении происходит утечка памяти, а Вы об этом не знаете

Следующая Статья

Новое в Symfony 6.4: CHIPS Cookie