Регулярные выражения в JavaScript: освоение шаблонов для текста

Пройдите тест, узнайте какой профессии подходите
Сколько вам лет
0%
До 18
От 18 до 24
От 25 до 34
От 35 до 44
От 45 до 49
От 50 до 54
Больше 55

Для кого эта статья:

  • Начинающие и средние веб-разработчики, стремящиеся улучшить свои навыки программирования
  • Специалисты по обработке данных и анализа текста
  • Студенты и обучающиеся в области информационных технологий, интересующиеся практическим применением инструментов программирования

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

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

Что такое регулярные выражения и зачем они нужны

Регулярные выражения (RegExp) — это шаблоны, используемые для поиска комбинаций символов в строках. В JavaScript они представляют собой объекты, которые можно создавать с помощью литерала регулярного выражения или конструктора RegExp.

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

Алексей Семенов, Senior Frontend Developer

Однажды я получил задачу извлечь все URL-адреса из нескольких тысяч строк пользовательского контента. Первоначально я использовал серию string.indexOf() и substring(), создав монструозную функцию в 200 строк, которая всё равно не учитывала все возможные форматы URL. Когда мой коллега показал решение с регулярным выражением в 1 строку, которое безупречно справлялось со всеми случаями, я понял, что игнорировать регулярки — непозволительная роскошь для профессионального разработчика.

Основные преимущества регулярных выражений:

  • Лаконичность — сложные операции с текстом можно выполнить в одной строке кода
  • Гибкость — возможность создания шаблонов для любых текстовых структур
  • Производительность — оптимизированные алгоритмы сопоставления работают быстрее ручных реализаций
  • Универсальность — знание регулярных выражений применимо практически во всех языках программирования

Типичные задачи, где регулярные выражения незаменимы:

Задача Без регулярных выражений С регулярными выражениями
Валидация email Десятки строк проверок различных частей адреса Одна строка с шаблоном
Извлечение данных из текста Сложные комбинации string.indexOf(), substring() Шаблон с группами захвата
Форматирование строк Множественные проверки и замены Один вызов string.replace()
Разбор URL-параметров Парсинг строки вручную Шаблон, извлекающий все параметры сразу
Пошаговый план для смены профессии

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

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

Литеральный синтаксис (предпочтительный для константных шаблонов):

JS
Скопировать код
const regex = /pattern/flags;

Конструктор (полезен, когда шаблон генерируется динамически):

JS
Скопировать код
const regex = new RegExp('pattern', 'flags');

Давайте разберем основные элементы синтаксиса регулярных выражений, которые необходимо знать каждому JavaScript-разработчику. 🧩

Базовые символы и метасимволы

  • . — любой символ, кроме новой строки
  • ^ — начало строки
  • $ — конец строки
  • \d — цифра (эквивалент [0-9])
  • \w — буквенно-цифровой символ или подчеркивание (эквивалент [a-zA-Z0-9_])
  • \s — пробельный символ
  • \D, \W, \S — отрицания соответствующих метасимволов

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

JS
Скопировать код
// Проверка, является ли строка числом
const isNumber = /^\d+$/.test('12345'); // true

// Проверка наличия пробелов
const hasSpaces = /\s/.test('Hello World'); // true

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

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

  • * — 0 или более раз
  • + — 1 или более раз
  • ? — 0 или 1 раз
  • {n} — ровно n раз
  • {n,} — n или более раз
  • {n,m} — от n до m раз

Примеры с квантификаторами:

JS
Скопировать код
// Проверка формата телефонного номера: XXX-XXX-XXXX
const isPhoneNumber = /^\d{3}-\d{3}-\d{4}$/.test('123-456-7890'); // true

// Проверка имени пользователя (3-16 символов, буквы, цифры и подчеркивания)
const isValidUsername = /^\w{3,16}$/.test('user_123'); // true

Группы и альтернативы

Группы позволяют объединять части выражения и извлекать совпадения:

  • (xyz) — группа захвата
  • (?:xyz) — группа без захвата
  • x|y — альтернатива (x или y)
JS
Скопировать код
// Извлечение имени и домена из email
const emailRegex = /^([a-z0-9_.]+)@([a-z0-9]+\.[a-z]{2,})$/i;
const matches = 'user.name@example.com'.match(emailRegex);
console.log(matches[1]); // 'user.name'
console.log(matches[2]); // 'example.com'

// Проверка, содержит ли строка 'javascript' или 'typescript'
const hasJSorTS = /java(script|Script)|type(script|Script)/.test('JavaScript guide'); // true

Флаги регулярных выражений

Флаги модифицируют поведение регулярных выражений:

Флаг Описание Пример
i Регистронезависимый поиск /hello/i.test('Hello') // true
g Глобальный поиск (все совпадения) 'abc abc'.match(/abc/g) // ['abc', 'abc']
m Многострочный режим /^line/m.test('text\nline') // true
s Режим "точка соответствует всему" /a.c/s.test('a\nc') // true
u Юникод /\u{1F600}/u.test('😀') // true
y "Липкий" режим (поиск с указанной позиции) Используется с методом exec() и lastIndex

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

JavaScript предоставляет несколько методов для работы с регулярными выражениями как через объект RegExp, так и через методы строк. Эти методы позволяют выполнять различные операции: от простой проверки наличия совпадений до сложной обработки текста. 🔍

Методы объекта RegExp

  • test() — проверяет наличие совпадений в строке, возвращает boolean
  • exec() — ищет совпадение в строке, возвращает массив с информацией о совпадении или null

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

JS
Скопировать код
// test() – проверка валидности email
const emailRegex = /^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$/i;
console.log(emailRegex.test('user@example.com')); // true
console.log(emailRegex.test('invalid-email')); // false

// exec() – извлечение информации о совпадениях
const urlRegex = /https?:\/\/(www\.)?([a-z0-9.-]+)\.([a-z]{2,})(\/[^\/\s]*)*\/?/i;
const result = urlRegex.exec('Visit https://developer.mozilla.org/en-US/docs/Web/JavaScript');
console.log(result[2]); // 'developer.mozilla'
console.log(result[3]); // 'org'

Метод exec() особенно полезен при работе с глобальным флагом g, так как позволяет последовательно получать все совпадения:

JS
Скопировать код
const regex = /\d+/g;
const text = 'There are 3 apples and 5 oranges';
let match;

while ((match = regex.exec(text)) !== null) {
console.log(`Found ${match[0]} at position ${match.index}`);
}
// Found 3 at position 10
// Found 5 at position 25

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

  • match() — находит все совпадения в строке
  • matchAll() — возвращает итератор по всем совпадениям с подробной информацией
  • search() — ищет совпадение и возвращает индекс первого совпадения
  • replace() — заменяет совпадения на указанную строку или результат функции
  • replaceAll() — заменяет все совпадения (нужен флаг g)
  • split() — разбивает строку по разделителю, заданному регулярным выражением

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

JS
Скопировать код
// match() – извлечение всех чисел из строки
const numbers = 'The price is $23.99, but was $30.50 last week'.match(/\d+\.\d+/g);
console.log(numbers); // ['23.99', '30.50']

// replace() – форматирование телефонного номера
const formattedPhone = '1234567890'.replace(/(\d{3})(\d{3})(\d{4})/, '($1) $2-$3');
console.log(formattedPhone); // '(123) 456-7890'

// split() – разбиение строки по нескольким разделителям
const words = 'apple,orange;banana|grape'.split(/[,;|]/);
console.log(words); // ['apple', 'orange', 'banana', 'grape']

Дмитрий Волков, Lead JavaScript Developer

В проекте по обработке пользовательских комментариев мне требовалось идентифицировать и преобразовывать различные типы ссылок: YouTube-видео, URLs, упоминания пользователей. Первый подход с использованием серии условных проверок приводил к нечитаемому коду и постоянным баг-фиксам. Переписав решение с использованием регулярных выражений и метода replace() с функцией обратного вызова, я сократил код втрое и увеличил производительность на 40%. Особенно элегантным оказалось использование именованных групп захвата (?<name>...), которые сделали обработку различных компонентов URL интуитивно понятной. Именно эта задача показала мне, насколько мощным инструментом могут быть регулярные выражения при правильном использовании.

Расширенные техники работы с методами

Одна из самых мощных техник — использование функции обратного вызова с методом replace():

JS
Скопировать код
// Конвертация дат из формата MM/DD/YYYY в YYYY-MM-DD
const dateText = 'Meeting scheduled for 12/25/2023 and 01/15/2024';
const isoDateText = dateText.replace(/(\d{2})\/(\d{2})\/(\d{4})/g, (match, month, day, year) => {
return `${year}-${month}-${day}`;
});
console.log(isoDateText); // 'Meeting scheduled for 2023-12-25 and 2024-01-15'

Метод matchAll() для получения всей информации о совпадениях:

JS
Скопировать код
const text = 'Email me at john@example.com or contact support@company.io';
const emailRegex = /([a-z0-9._%+-]+)@([a-z0-9.-]+)\.([a-z]{2,})/gi;
const emails = Array.from(text.matchAll(emailRegex));

emails.forEach(match => {
console.log(`Full email: ${match[0]}`);
console.log(`Username: ${match[1]}`);
console.log(`Domain: ${match[2]}.${match[3]}`);
});

Практические задачи: от валидации форм до обработки текста

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

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

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

JS
Скопировать код
// Валидация email
function validateEmail(email) {
const regex = /^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$/i;
return regex.test(email);
}

// Валидация пароля (минимум 8 символов, хотя бы одна буква и одна цифра)
function validatePassword(password) {
const regex = /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$/;
return regex.test(password);
}

// Валидация URL
function validateURL(url) {
const regex = /^(https?:\/\/)?(www\.)?[a-z0-9-]+(\.[a-z]{2,})+([\/\w-]*)*\/?$/i;
return regex.test(url);
}

Извлечение данных из текста

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

JS
Скопировать код
// Извлечение всех хештегов из текста
function extractHashtags(text) {
const regex = /#[a-z0-9_]+/gi;
return text.match(regex) || [];
}

// Извлечение ссылок
function extractLinks(text) {
const regex = /https?:\/\/[^\s]+/g;
return text.match(regex) || [];
}

// Извлечение цитат (текст в кавычках)
function extractQuotes(text) {
const regex = /"([^"]*)"/g;
const quotes = [];
let match;

while ((match = regex.exec(text)) !== null) {
quotes.push(match[1]);
}

return quotes;
}

Форматирование и преобразование текста

Метод replace() с регулярными выражениями позволяет элегантно трансформировать текст.

JS
Скопировать код
// Форматирование телефонных номеров
function formatPhoneNumber(phone) {
// Удаляем все нецифровые символы
const cleaned = phone.replace(/\D/g, '');

// Форматируем номер в виде (XXX) XXX-XXXX
return cleaned.replace(/(\d{3})(\d{3})(\d{4})/, '($1) $2-$3');
}

// Преобразование snake_case в camelCase
function snakeToCamel(text) {
return text.replace(/_([a-z])/g, (match, letter) => letter.toUpperCase());
}

// Маскирование номера кредитной карты (отображаем только последние 4 цифры)
function maskCreditCard(cardNumber) {
// Удаляем все нецифровые символы
const cleaned = cardNumber.replace(/\D/g, '');

// Маскируем все, кроме последних 4 цифр
return cleaned.replace(/^(.*)(.{4})$/, '••••-••••-••••-$2');
}

Разбор и манипуляция с HTML/XML

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

JS
Скопировать код
// Извлечение всех ссылок из HTML-текста
function extractHtmlLinks(html) {
const regex = /<a\s+(?:[^>]*?\s+)?href="([^"]*)"[^>]*>(.*?)<\/a>/gi;
const links = [];
let match;

while ((match = regex.exec(html)) !== null) {
links.push({
url: match[1],
text: match[2]
});
}

return links;
}

// Удаление HTML-тегов из текста
function stripHtmlTags(html) {
return html.replace(/<[^>]*>/g, '');
}

Задача Регулярное выражение Пример
Валидация email /^[a-z0-9._%+-]+@[a-z0-9.-]+.[a-z]{2,}$/i user.name@example.com
Валидация URL /^(https?://)?(www.)?[a-z0-9-]+(.[a-z]{2,})+[/\w-]*/?$/i https://example.com/page
Валидация пароля /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$/ SecurePass123
Форматирование телефона /(\d{3})(\d{3})(\d{4})/ (123) 456-7890
Извлечение хештегов /#[a-z0-9_]+/gi #javascript #regexp

Типичные ошибки и как их избежать при создании регулярок

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

Проблемы с жадными квантификаторами

По умолчанию квантификаторы (*, +, ?, {n,m}) являются "жадными" — они стремятся захватить максимально возможное количество символов.

JS
Скопировать код
// Проблема: жадное поведение
const html = '<div>First</div><div>Second</div>';
const greedyRegex = /<div>.*<\/div>/;
console.log(html.match(greedyRegex)[0]); // '<div>First</div><div>Second</div>'

// Решение: ленивый квантификатор
const lazyRegex = /<div>.*?<\/div>/g;
console.log(html.match(lazyRegex)); // ['<div>First</div>', '<div>Second</div>']

Добавление ? после квантификатора делает его "ленивым", что часто является правильным подходом при работе с HTML.

Неправильное экранирование специальных символов

Метасимволы (. ^ $ * + ? ( ) [ ] { } | \) имеют специальное значение и должны быть экранированы, если нужно их буквальное значение.

JS
Скопировать код
// Проблема: неэкранированные метасимволы
const regex1 = /price: $10.99/; // Ошибка: $ интерпретируется как "конец строки"

// Решение: экранирование метасимволов
const regex2 = /price: \$10\.99/;

// Альтернатива: использование String.raw для более читаемого кода
const regex3 = new RegExp(String.raw`price: \$10\.99`);

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

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

JS
Скопировать код
// Проблема: лишние группы захвата
const dateRegex1 = /([0-9]{4})-([0-9]{2})-([0-9]{2})/;

// Решение: используйте группы без захвата, когда данные не нужны
const dateRegex2 = /(?:[0-9]{4})-([0-9]{2})-([0-9]{2})/;

// Или именованные группы для большей ясности
const dateRegex3 = /(?<year>[0-9]{4})-(?<month>[0-9]{2})-(?<day>[0-9]{2})/;
const match = '2023-12-25'.match(dateRegex3).groups;
console.log(match.year, match.month, match.day); // 2023 12 25

Проблемы с производительностью

Некоторые шаблоны могут привести к "катастрофическому отступлению" — экспоненциальному росту времени выполнения.

JS
Скопировать код
// Проблема: шаблон с потенциальной уязвимостью производительности
const badRegex = /^(a+)+$/;
// На строке 'aaaaaaaaaaaaaaaaaaaaaaaaaX' вызовет зависание

// Решение: более эффективный шаблон
const goodRegex = /^a+$/;

Вложенные повторяющиеся группы ((a+)+) — частый источник проблем. Старайтесь избегать таких конструкций.

Ошибки при использовании границ слова

Метасимвол \b обозначает границу слова, но его поведение не всегда интуитивно понятно.

JS
Скопировать код
// Проблема: неожиданное поведение границ слова
const regex1 = /\bcat\b/;
console.log(regex1.test('The cat is here')); // true
console.log(regex1.test('category')); // false (как и ожидалось)
console.log(regex1.test('The cat's toy')); // false (неожиданно!)

// Решение: более точное определение того, что является "словом"
const regex2 = /(?<=\s|^)cat(?=\s|'s|$)/;

Советы по избеганию ошибок

  • Тестируйте на граничных случаях — создавайте тесты для пустых строк, неожиданных входных данных и граничных случаев
  • Разбивайте сложные шаблоны — для улучшения читаемости и упрощения отладки
  • Используйте инструменты визуализации — сайты вроде regex101.com помогают понять, как работает ваше выражение
  • Документируйте сложные регулярные выражения — поясняйте, что делают различные части шаблона
  • Используйте флаг x (в комбинации с конструктором RegExp) — позволяет добавлять комментарии и пробелы в шаблон
JS
Скопировать код
// Пример документированного регулярного выражения с флагом x
const passwordRegex = new RegExp(`
^ # Начало строки
(?=.*[A-Z]) # По крайней мере одна заглавная буква
(?=.*[a-z]) # По крайней мере одна строчная буква
(?=.*[0-9]) # По крайней мере одна цифра
(?=.*[!@#$%^&*]) # По крайней мере один спецсимвол
.{8,} # Не менее 8 символов
$ # Конец строки
`, 'x');

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

Читайте также

Проверь как ты усвоил материалы статьи
Пройди тест и узнай насколько ты лучше других читателей
Что такое регулярные выражения в JavaScript?
1 / 5

Загрузка...