Регулярные выражения в TypeScript: от теории к практике
Регулярные выражения (RegExp) — мощный инструмент для поиска, замены и валидации строк. В TypeScript они работают так же, как в JavaScript, но добавляют строгую типизацию, что упрощает отладку и повышает надёжность кода. В этой статье мы разберём синтаксис, методы и реальные примеры использования регулярных выражений в TypeScript.
Создание регулярных выражений в TypeScript
В TypeScript существует два способа создания RegExp: литеральный и через конструктор. Оба варианта типизированы и возвращают объект типа RegExp.
Литеральный синтаксис
Самый простой и часто используемый способ — заключить шаблон в косые черты. Флаги указываются после второй черты.
// Поиск слова "hello" без учёта регистра
const pattern: RegExp = /hello/i;
console.log(pattern.test('Hello World')); // true
Конструктор RegExp
Конструктор удобен, когда шаблон формируется динамически. Первый аргумент — строка с паттерном, второй — флаги.
const searchTerm: string = 'TypeScript';
const dynamicPattern: RegExp = new RegExp(searchTerm, 'gi');
console.log('I love TypeScript and TypeScript is great'.match(dynamicPattern));
// ['TypeScript', 'TypeScript']
Основные методы RegExp в TypeScript
TypeScript наследует все методы JavaScript для работы с регулярками. Рассмотрим самые популярные.
test() — проверка наличия
Метод test() возвращает true или false. Полезен для валидации форм.
const emailRegex: RegExp = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
const email: string = 'user@example.com';
console.log(emailRegex.test(email)); // true
exec() — детальный поиск
exec() возвращает массив с совпадением, индексом и группами. Если совпадений нет — null.
const datePattern: RegExp = /(\d{2})\.(\d{2})\.(\d{4})/;
const result: RegExpExecArray | null = datePattern.exec('Сегодня 15.03.2025');
if (result) {
console.log(`День: ${result[1]}, Месяц: ${result[2]}, Год: ${result[3]}`);
// День: 15, Месяц: 03, Год: 2025
}
match() и matchAll() для строк
Метод match() вызывается у строки и принимает RegExp. Для глобального поиска всех совпадений используйте matchAll().
const text: string = 'Код 123, код 456, код 789';
const numbers: RegExpMatchArray | null = text.match(/\d+/g);
console.log(numbers); // ['123', '456', '789']
// matchAll() возвращает итератор
const matches: IterableIterator<RegExpMatchArray> = text.matchAll(/(\d+)/g);
for (const match of matches) {
console.log(`Найдено число: ${match[1]}`);
}
Практические примеры регулярных выражений в TypeScript
Теперь применим теорию на реальных задачах. Все примеры написаны с учётом строгой типизации TypeScript.
Пример 1: Валидация email-адреса
Создадим функцию, которая проверяет корректность email. Используем типизированное регулярное выражение.
function isValidEmail(email: string): boolean {
const emailRegex: RegExp = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
console.log(isValidEmail('test@mail.ru')); // true
console.log(isValidEmail('invalid-email')); // false
Пример 2: Извлечение чисел из строки
Часто нужно получить все числа из текста. Используем глобальный поиск с флагом g.
function extractNumbers(text: string): number[] {
const numberPattern: RegExp = /\d+/g;
const matches: RegExpMatchArray | null = text.match(numberPattern);
return matches ? matches.map(Number) : [];
}
const result: number[] = extractNumbers('Цена: 2500 руб, скидка 300 руб');
console.log(result); // [2500, 300]
Пример 3: Замена с помощью replace()
Метод replace() позволяет заменять совпадения. Можно использовать строку или функцию обратного вызова.
function censorBadWords(text: string, badWords: string[]): string {
const pattern: RegExp = new RegExp(badWords.join('|'), 'gi');
return text.replace(pattern, (match: string) => '*'.repeat(match.length));
}
const cleanText: string = censorBadWords('Это плохой пример и ужасный код', ['плохой', 'ужасный']);
console.log(cleanText); // 'Это ****** пример и ******* код'
Пример 4: Парсинг URL
Разберём URL на составные части с помощью групп захвата.
interface ParsedUrl {
protocol: string;
domain: string;
path: string;
}
function parseUrl(url: string): ParsedUrl | null {
const urlPattern: RegExp = /^(https?):\/\/([^\/]+)(\/.*)?$/;
const match: RegExpExecArray | null = urlPattern.exec(url);
if (!match) return null;
return {
protocol: match[1],
domain: match[2],
path: match[3] || '/'
};
}
const parsed: ParsedUrl | null = parseUrl('https://pythonlib.ru/articles');
console.log(parsed);
// { protocol: 'https', domain: 'pythonlib.ru', path: '/articles' }
Оптимизация и типизация регулярных выражений
TypeScript помогает избежать ошибок на этапе компиляции. Вот несколько советов:
- Используйте типы: явно указывайте
RegExpдля переменных. - Проверяйте на null: методы
exec()иmatch()могут вернутьnull. Всегда проверяйте результат. - Избегайте медленных паттернов: например,
.*с жадными квантификаторами может вызвать катастрофический возврат (backtracking). - Комментируйте сложные выражения: используйте флаг
x(расширенный режим) для читаемости, но в TypeScript он пока не