Регулярные выражения в JavaScript: Полный гайд и шпаргалка
-
Зачем нужны регулярные выражения?
Регулярные выражения (regex) — это мощный инструмент для поиска, проверки и преобразования текста по определённым шаблонам. Без них разработчику пришлось бы писать громоздкий код с множеством условий.
Примеры использования:
- Валидация email, номеров телефонов, URL
- Поиск и замена текста по шаблону
- Парсинг и извлечение данных из строк
- Обработка лог-файлов
- Форматирование данных
Быстрый пример:
// Без regex — много условий и цикловых конструкций // Валидация email вручную — сложно и ненадёжно // С regex — одна строка const isValidEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
Основы: Как создать регулярное выражение
Два способа создания
1. Литеральная нотация (предпочтительно для статичных паттернов)
const pattern = /hello/;2. Конструктор RegExp (для динамических паттернов)
const pattern = new RegExp('hello'); const userPattern = new RegExp(`${userInput}`, 'gi');Используйте литеральную нотацию, когда паттерн известен заранее — она быстрее. Конструктор нужен, когда паттерн строится динамически из переменных.
Флаги: Управление поведением
Флаги добавляются после паттерна и изменяют способ поиска:
Флаг Описание Пример gGlobal — найти все совпадения, не только первое /cat/gнаходит все “cat” в строкеiIgnore case — игнорировать регистр /hello/iнайдёт “Hello”, “HELLO”, “hello”mMultiline — ^и$работают для каждой строки/^start/mнайдёт “start” в начале каждой строкиsDotall — точка .будет совпадать с переносом строки/a.b/sнайдёт “a\nb”uUnicode — правильная работа с Unicode символами /\p{L}/uнайдёт любую буквуdIndices — получить позиции совпадений использует свойство indicesКомбинирование флагов:
const pattern = /hello/gi; // Глобальный поиск, игнорируя регистр const str = 'Hello there, HELLO world'; console.log(str.match(pattern)); // ['Hello', 'HELLO']
Символы и классы: Что искать
Простые символы
/abc/.test('abc'); // true — ищем точную последовательность /abc/.test('abcd'); // true — "abc" есть в строке /abc/.test('ab c'); // false — нет точной последовательностиСпециальные символы (метасимволы)
Символ Значение Пример .Любой символ (кроме переноса строки) /a.c/совпадает с “abc”, “adc”, но не “a\nc”^Начало строки /^hello/только если строка начинается с “hello”$Конец строки /world$/только если строка заканчивается на “world”\Экранирование специального символа /a\.b/ищет букв “a”, точку и “b” буквальноПримеры:
// Начало и конец строки /^hello/.test('hello world'); // true /^hello/.test('say hello'); // false /world$/.test('hello world'); // true // Точка — любой символ /a.c/.test('abc'); // true /a.c/.test('adc'); // true /a.c/.test('a\nc'); // false (нужен флаг 's')Классы символов:
[...]— выбор из набораКвадратные скобки означают “любой один символ из списка”:
// Одиночные символы /[aeiou]/.test('hello'); // true (буква 'e') /[0-9]/.test('abc123'); // true (цифра '1') // Диапазоны /[a-z]/.test('hello'); // true (любая строчная буква) /[A-Z]/.test('Hello'); // true (прописная буква) /[0-9]/.test('test2'); // true (цифра) // Инверсия (всё кроме указанного) /[^aeiou]/.test('hello'); // true (согласная буква)Встроенные классы: Сокращения для популярных наборов
Класс Эквивалент Описание \d[0-9]Цифра \D[^0-9]Не цифра \w[A-Za-z0-9_]Буква, цифра или подчёркивание (word character) \W[^A-Za-z0-9_]Не буква/цифра \s[ \t\n\r\f]Пробел или табуляция \S[^ \t\n\r\f]Не пробел \b— Граница слова (между буквой и не-буквой) \B— Не граница слова Практические примеры:
// Найти все цифры в строке 'abc123def456'.match(/\d/g); // ['1', '2', '3', '4', '5', '6'] // Найти все слова 'hello world 123'.match(/\w+/g); // ['hello', 'world', '123'] // Пробелы 'hello world'.split(/\s+/); // ['hello', 'world'] // Только в начале слова 'par spar apart'.replace(/\bpar/g, 'X'); // 'X spar aX' — заменяет только целые слова
Квантификаторы: Количество повторений
Квантификаторы указывают, сколько раз должен повториться предыдущий символ или группа:
Квантификатор Значение Пример ?0 или 1 раз (опционально) /colou?r/совпадает с “color” и “colour”*0 или больше раз /ab*c/совпадает с “ac”, “abc”, “abbc”+1 или больше раз /ab+c/совпадает с “abc”, “abbc”, но не “ac”{n}Точно n раз /a{3}/совпадает только с “aaa”{n,}n или больше раз /a{2,}/совпадает с “aa”, “aaa”, “aaaa”{n,m}От n до m раз /a{2,4}/совпадает с “aa”, “aaa” или “aaaa”Примеры:
// Опциональные символы const phonePattern = /\d{3}-?\d{3}-?\d{4}/; phonePattern.test('123-456-7890'); // true phonePattern.test('1234567890'); // true // Пароль: минимум 8 символов /^.{8,}$/.test('mypass123'); // true // Телефон США /^\(?[0-9]{3}\)?[-. ]?[0-9]{3}[-. ]?[0-9]{4}$/.test('(123) 456-7890'); // true // Одна или больше цифр '123abc456'.match(/\d+/g); // ['123', '456']
Группы и захват: Выделение части совпадения
Группы для логики
// Группа группирует для квантификаторов /(ab)+/.test('ababab'); // true /(ab)+/.test('abac'); // false // Или внутри группы /(cat|dog)/.test('I have a cat'); // true /col(ou)?r/.test('color'); // true /col(ou)?r/.test('colour'); // trueЗахватывающие группы: Извлечение данных
Скобки
()создают “захватывающую группу” — часть совпадения, которую потом можно использовать:// Извлечение частей совпадения const email = 'john@example.com'; const match = email.match(/([a-z]+)@([a-z.]+)/); console.log(match[0]); // 'john@example.com' (полное совпадение) console.log(match[1]); // 'john' (первая группа) console.log(match[2]); // 'example.com' (вторая группа) // В replace — используем группы через $1, $2 и т.д. 'John Smith'.replace(/(\w+) (\w+)/, '$2, $1'); // 'Smith, John' // Дата: преобразование из YYYY-MM-DD в DD.MM.YYYY '2025-01-15'.replace(/(\d{4})-(\d{2})-(\d{2})/, '$3.$2.$1'); // '15.01.2025'Неzахватывающие группы:
(?:...)Когда нужна группа для логики, но не нужно сохранять совпадение:
// С захватом (создаёт группу 1) /(cat|dog) \1/.test('cat cat'); // true (говорит: повторить то же слово) // Без захвата — просто группировка const color = /(red|green|blue)/; const result = 'I like green'.match(color); console.log(result[1]); // 'green' // Когда захват не нужен /(?:https?|ftp):\/\//.test('https://example.com'); // true 'files.txt, images.png'.match(/\.(?:txt|png|jpg)/g); // ['.txt', '.png']Именованные группы: Читаемость кода
const datePattern = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/; const date = '2025-01-15'; const match = date.match(datePattern); console.log(match.groups.year); // '2025' console.log(match.groups.month); // '01' console.log(match.groups.day); // '15' // В replace используем $<name> '2025-01-15'.replace(datePattern, '$<day>.$<month>.$<year>'); // '15.01.2025'
Backreference: Ссылка на уже найденное
Backreference
\1,\2и т.д. означают “повтори то же, что нашли в группе 1, 2 и т.д.”:// Найти повторяющиеся слова /\b(\w+) \1\b/.test('the the'); // true /\b(\w+) \1\b/.test('the cat'); // false // Убрать повторяющиеся слова 'hello hello world world test'.replace(/\b(\w+) \1+\b/g, '$1'); // 'hello world test' // Фигурные скобки: найти две одинаковые цифры подряд /(\d)\1/.test('11'); // true /(\d)\1/.test('12'); // false // Скобки вокруг одного и того же /([([]))\1/.test('(())'); // true
Lookahead и Lookbehind: Условные совпадения
Lookahead и lookbehind — это “нулевой ширины” проверки. Они проверяют, есть ли что-то дальше или раньше, но не включают это в совпадение.
Positive lookahead
(?=...)“Совпадает, если дальше идёт…”
// Найти цифры, которые идут перед словом "miles" '5 miles, 10 kilometers'.match(/\d+(?= miles)/g); // ['5'] // Пароль содержит минимум одну цифру /(?=.*\d)/.test('password123'); // true (дальше идут цифры) /(?=.*\d)/.test('password'); // false // Числа перед запятой или концом '5, 10, 15'.match(/\d+(?=[,]|$)/g); // ['5', '10', '15']Negative lookahead
(?!...)“Совпадает, если дальше НЕ идёт…”
// Найти "cat", которые НЕ следуют перед цифрой 'cat, cat1, cat2'.match(/cat(?!\d)/g); // ['cat'] // Слова, не являющиеся числами 'hello 123 world'.match(/\w+(?!\d)/g); // ['hello', 'world'] // URL без https 'http://example.com, https://secure.com'.match(/https?:\/\/(?!https)/g);Positive lookbehind
(?<=...)“Совпадает, если перед этим идёт…”
// Цифры, которые идут после доллара '$5, €10, $20'.match(/(?<=\$)\d+/g); // ['5', '20'] // Слово, которому предшествует точка 'Dr. Smith'.match(/(?<=\.)[\w\s]+/); // [' Smith']Negative lookbehind
(?<!...)“Совпадает, если перед этим НЕ идёт…”
// Слова, которым НЕ предшествует двоеточие 'name: John, age: 25, city: Moscow'.match(/(?<!:)\s(\w+)/g); // Цены без валюты '$10 free! €20 paid'.match(/(?<!\$)\d+/g); // ['20'] в контекстеПрактический пример с lookaround:
// Валидация пароля: минимум 8 символов, буква и цифра const passwordRegex = /^(?=.*[a-zA-Z])(?=.*\d).{8,}$/; passwordRegex.test('password1'); // true passwordRegex.test('password'); // false (нет цифры) passwordRegex.test('pass1'); // false (меньше 8)
Методы работы с regex в JavaScript
test()— Проверка на совпадениеВозвращает
trueилиfalse:const pattern = /hello/; pattern.test('hello world'); // true pattern.test('goodbye world'); // falsematch()— Найти все совпаденияВозвращает массив совпадений или
null:// Без флага 'g' — только первое совпадение с деталями 'hello hello hello'.match(/hello/); // ['hello', index: 0, groups: undefined, input: 'hello hello hello'] // С флагом 'g' — все совпадения, но без деталей 'hello hello hello'.match(/hello/g); // ['hello', 'hello', 'hello'] // С группами 'john@example.com jane@test.com'.match(/(\w+)@(\w+)/g); // ['john@example.com', 'jane@test.com']matchAll()— Итератор по всем совпадениямconst str = 'test1 test2 test3'; const pattern = /test(\d)/g; const matches = Array.from(str.matchAll(pattern)); matches.forEach(match => { console.log(match[0]); // полное совпадение console.log(match[1]); // первая группа console.log(match.index); // позиция });search()— Позиция первого совпаденияВозвращает индекс или -1:
'hello world'.search(/world/); // 6 'hello world'.search(/xyz/); // -1replace()— Заменить первое совпадение'hello hello'.replace(/hello/, 'hi'); // 'hi hello' 'hello hello'.replace(/hello/g, 'hi'); // 'hi hi' // С функцией-обработчиком '5 and 10'.replace(/\d+/g, (match) => { return parseInt(match) * 2; }); // '10 and 20'replaceAll()— Заменить все совпадения'hello hello'.replaceAll('hello', 'hi'); // 'hi hi' // Эквивалент: replace(/hello/g, 'hi')split()— Разбить строку по паттерну// Разделитель 'a,b;c:d'.split(/[,;:]/); // ['a', 'b', 'c', 'd'] // С захватывающими группами — включить разделители 'a1b2c3'.split(/(\d)/); // ['a', '1', 'b', '2', 'c', '3'] // Множественные пробелы 'hello world test'.split(/\s+/); // ['hello', 'world', 'test']exec()— Детальный поискВозвращает подробный результат или null:
const pattern = /(\d{3})-(\d{3})-(\d{4})/; const match = pattern.exec('My phone: 555-123-4567'); match[0]; // '555-123-4567' (полное совпадение) match[1]; // '555' (первая группа) match[2]; // '123' match[3]; // '4567' match.index; // 10 (где начинается совпадение)
Практические примеры из реальной жизни
Валидация email
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; emailPattern.test('user@example.com'); // true emailPattern.test('invalid.email@'); // falseВалидация телефона
// Формат: (XXX) XXX-XXXX или XXX-XXX-XXXX const phonePattern = /^(\+1)?[-.\s]?\(?[0-9]{3}\)?[-.\s]?[0-9]{3}[-.\s]?[0-9]{4}$/; phonePattern.test('(555) 123-4567'); // true phonePattern.test('555-123-4567'); // true phonePattern.test('+1-555-123-4567'); // trueИзвлечение всех URL из текста
const text = 'Visit https://example.com and http://test.org'; const urls = text.match(/https?:\/\/[^\s]+/g); // ['https://example.com', 'http://test.org']Парсинг даты и преобразование формата
// ISO (YYYY-MM-DD) в локальный (DD.MM.YYYY) '2025-01-15 2025-12-25'.replace(/(\d{4})-(\d{2})-(\d{2})/g, '$3.$2.$1'); // '15.01.2025 25.12.2025'Удаление HTML тегов
const html = '<p>Hello <b>world</b>!</p>'; html.replace(/<[^>]*>/g, ''); // 'Hello world!'Каждое слово с заглавной буквы (Title Case)
function titleCase(str) { return str.replace(/\b\w/g, (match) => match.toUpperCase()); } titleCase('hello world javascript'); // 'Hello World Javascript'Форматирование цены (добавление разделителей)
const price = '1000000'; price.replace(/\B(?=(\d{3})+(?!\d))/g, ' '); // '1 000 000' // Или: price.replace(/(\d)(?=(\d{3})+$)/g, '$1 '); // '1 000 000'Валидация пароля (сложный пример)
// Минимум 8 символов, минимум одна буква, одна цифра, один спецсимвол const passwordPattern = /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/; passwordPattern.test('Pass123!'); // true passwordPattern.test('password'); // false (нет цифры и спецсимвола) passwordPattern.test('Pass1'); // false (меньше 8 символов)Замена значений в объекте
const config = 'name=john&age=25&city=moscow'; config.replace(/([^=&]+)=([^&]*)/g, (match, key, value) => { console.log(`${key}: ${value}`); return match; }); // name: john // age: 25 // city: moscow
Частые ошибки и как их избежать
1. Забыли флаг
g— заменилось только первое совпадение// ❌ Неправильно 'hello hello'.replace(/hello/, 'hi'); // 'hi hello' // ✅ Правильно 'hello hello'.replace(/hello/g, 'hi'); // 'hi hi'2. Не экранировали спецсимволы
// ❌ Неправильно — точка совпадает с любым символом /a.b/.test('a b'); // true (нежелательно) // ✅ Правильно /a\.b/.test('a.b'); // true /a\.b/.test('a b'); // false3. Забыли
^и$— совпадение может быть частью строки// ❌ Неправильно /^[0-9]+$/.test('abc123def'); // false (но хотели false) /[0-9]+/.test('abc123def'); // true (число есть, но не только число) // ✅ Правильно /^\d+$/.test('123'); // true (только цифры) /^\d+$/.test('123abc'); // false (есть буквы)4. Жадные квантификаторы вместо ленивых
// ❌ Жадное — захватывает слишком много '<p>Hello</p> <b>Bold</b>'.match(/<.*>/g); // ['<p>Hello</p> <b>Bold</b>'] — одно совпадение вместо двух // ✅ Ленивое — `?` после квантификатора '<p>Hello</p> <b>Bold</b>'.match(/<.*?>/g); // ['<p>', '</p>', '<b>', '</b>'] — правильно5. Забыли экранировать обратный слэш в конструкторе
// ❌ Неправильно new RegExp('\d+'); // Интерпретируется неправильно // ✅ Правильно new RegExp('\\d+'); // Экранируем слэш в строке // Или просто используйте литеральную нотацию: /\d+/;
Шпаргалка: Визуальный справочник
Краткая таблица символов
Что нужно Регулярное выражение Пример Любой символ .a.cсовпадает “abc”, “adc”Буква [a-zA-Z]или\p{L}(с флагом u)[a-z]совпадает “a” до “z”Цифра \d\d{3}совпадает “123”Не цифра \D\D+совпадает “abc”Пробел \s\s+совпадает " "Не пробел \S\S+совпадает “word”Слово \w\w+совпадает “hello_123”Граница слова \b\bhello\bтолько целое словоНачало ^^helloтолько в началеКонец $world$только в концеКвантификаторы (сколько повторений)
a? — ноль или один раз a* — ноль или больше a+ — один или больше a{3} — ровно 3 раза a{2,5} — от 2 до 5 раз a{2,} — минимум 2 раза a?? — ноль или один (ленивый) a*? — ноль или больше (ленивый) a+? — один или больше (ленивый)Методы String
str.test(regex) → true/false str.match(regex) → [совпадения] str.search(regex) → индекс или -1 str.replace(regex, new) → новая строка str.split(regex) → массив str.matchAll(regex) → итератор
Интерактивные инструменты и отладка
При разработке сложных regex используйте онлайн-инструменты:
- regex101.com — визуализация совпадений с объяснениями
- regexper.com — диаграмма паттерна
- regexpal.com — простой тестер
Совет: Стройте regex пошагово. Сначала простой паттерн, потом добавляйте сложность и тестируйте после каждого шага.
Заключение
Регулярные выражения — это мощный инструмент, который экономит время и код. Начните с простых паттернов и постепенно усложняйте. Благодаря lookahead, lookaround и группам, можно решать сложные задачи парсинга и валидации в одной строке.
Помните: лучший regex — это тот, который легко читать. Используйте именованные группы, комментарии в коде и тестируйте на реальных данных.
© 2024 - 2025 ExLends, Inc. Все права защищены.