DevToys Pro

бесплатные веб-инструменты для разработчиков

Блог
Оцените нас:
Попробуйте расширение для браузера:
← Назад к блогу

Поведение регулярных выражений с переносами строк в JavaScript

10 мин чтения

Обработка переносов строк в регулярных выражениях — один из самых запутанных аспектов сопоставления шаблонов. Поведение метасимволов таких как ., ^ и $ радикально меняется в зависимости от флагов regex, и разные языки программирования по-разному реализуют обработку переносов строк.

Это руководство фокусируется на поведении переносов строк в JavaScript regex, охватывая флаги DotAll (s) и Multiline (m), распространенные ошибки и практические паттерны для сопоставления текста, охватывающего несколько строк.

Метасимвол точка (.)

По умолчанию, точка (.) соответствует любому символу, кроме символов переноса строки (\n, \r).

Поведение по умолчанию

const text = "Привет\nМир";
const regex = /Привет.Мир/;

console.log(regex.test(text));  // false

// Точка не соответствует символу переноса строки

Использование флага DotAll (s)

Флаг s (также называемый "dotAll" или "single-line") заставляет точку соответствовать символам переноса строки:

const text = "Привет\nМир";
const regex = /Привет.Мир/s;  // Обратите внимание на флаг 's'

console.log(regex.test(text));  // true

// Теперь точка соответствует переносу строки

Важно: Флаг s был введен в ES2018. Для старых браузеров используйте [\s\S] или [^] вместо ..

Якоря: ^ и $

Якоря ^ (начало) и $ (конец) также ведут себя по-разному с переносами строк.

Поведение по умолчанию

Без флага multiline, ^ соответствует началу всей строки, а $ соответствует концу:

const text = "Строка 1\nСтрока 2\nСтрока 3";
const regex = /^Строка 2/;

console.log(regex.test(text));  // false

// ^Строка 2 ищет "Строка 2" в начале строки
// но строка начинается с "Строка 1"

Использование флага Multiline (m)

Флаг m меняет ^ и $ для соответствия началу и концу каждой строки:

const text = "Строка 1\nСтрока 2\nСтрока 3";
const regex = /^Строка 2/m;  // Обратите внимание на флаг 'm'

console.log(regex.test(text));  // true

// Теперь ^Строка 2 соответствует "Строка 2" в начале второй строки

Практический пример: Извлечение строк

const log = `
[INFO] Приложение запущено
[ERROR] Ошибка подключения к БД
[INFO] Повтор попытки...
[ERROR] Таймаут после 30с
`;

// Извлечь все строки ERROR
const errorRegex = /^\[ERROR\].*$/gm;
const errors = log.match(errorRegex);

console.log(errors);
// ["[ERROR] Ошибка подключения к БД", "[ERROR] Таймаут после 30с"]

Распространенные ошибки

Ошибка 1: Путаница флагов s и m

Названия не интуитивны:

  • Флаг s = "режим одной строки", но заставляет . соответствовать переносам строк (полезно для многострочного сопоставления)
  • Флаг m = "многострочный режим" и влияет на якоря ^ и $

Эти флаги независимы и могут комбинироваться:

const regex = /^.*$/sm;  // Оба флага вместе

// s: точка соответствует переносам строк
// m: ^ и $ соответствуют границам строк

Ошибка 2: Разные символы переноса строки

Разные операционные системы используют разные последовательности переноса строки:

  • Unix/Linux: \n (LF)
  • Windows: \r\n (CRLF)
  • Старый Mac: \r (CR)

Чтобы соответствовать любому варианту переноса строки:

// Соответствие любой последовательности переноса строки
const anyNewline = /\r?\n|\r/g;

// Разделение по любому переносу строки
const lines = text.split(/\r?\n|\r/);

// Альтернатива: используйте более полный паттерн
const lines2 = text.split(/\r\n|\n|\r/);

Ошибка 3: Жадное сопоставление через строки

При использовании флага s, жадные квантификаторы могут захватить слишком много:

const html = `
<div>Первый</div>
<div>Второй</div>
<div>Третий</div>
`;

// Попытка найти отдельные блоки <div>
const greedy = /<div>.*<\/div>/s;
console.log(html.match(greedy)[0]);
// Соответствует от первого <div> до ПОСЛЕДНЕГО </div> - вся строка!

// Используйте нежадное сопоставление
const nonGreedy = /<div>.*?<\/div>/gs;
console.log(html.match(nonGreedy));
// ["<div>Первый</div>", "<div>Второй</div>", "<div>Третий</div>"]

Практические паттерны

Паттерн 1: Соответствие всему между маркерами

// Извлечь содержимое между маркерами START и END (включая переносы строк)
const text = `
Некоторый текст
START
Важное содержимое
охватывающее несколько
строк
END
Еще текст
`;

const pattern = /START([\s\S]*?)END/;
const match = text.match(pattern);
console.log(match[1].trim());
// "Важное содержимое\nохватывающее несколько\nстрок"

// Современная альтернатива с флагом s
const pattern2 = /START(.*?)END/s;

Паттерн 2: Соответствие строк, начинающихся с определенного текста

const log = `
2026-01-11 10:00:00 INFO Сервер запущен
2026-01-11 10:00:15 ERROR Ошибка подключения
2026-01-11 10:00:20 INFO Повтор попытки
2026-01-11 10:00:25 ERROR Таймаут
`;

// Получить все строки ERROR
const errors = log.match(/^.*ERROR.*$/gm);
console.log(errors);

Тестирование ваших паттернов

При работе со сложными паттернами переносов строк, используйте DevToys Pro RegEx Tester для:

  • Тестирования паттернов с разными комбинациями флагов
  • Визуализации соответствий через несколько строк
  • Отладки жадного и нежадного поведения сопоставления
  • Экспериментов с разными последовательностями переносов строк

Лучшие практики

1. Будьте явными о флагах

// Плохо: неясно, какое поведение вы хотите
const pattern = /start.*end/;

// Хорошо: явно о обработке переносов строк
const pattern = /start.*?end/s;  // флаг s: точка соответствует переносам
const pattern2 = /^start.*end$/m;  // флаг m: ^ и $ для каждой строки

2. Используйте [\s\S] для широкой совместимости

// Если поддержка флага s неопределенна, используйте [\s\S]
const pattern = /start([\s\S]*?)end/;

// [\s\S] означает "любой пробельный или непробельный" = любой символ

3. Нормализуйте окончания строк когда возможно

// Нормализовать к \n перед обработкой
const normalized = text.replace(/\r\n|\r/g, '\n');

// Теперь можно использовать более простые паттерны
const lines = normalized.split('\n');

Заключение

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

  • Флаг s заставляет . соответствовать переносам строк (режим dotAll)
  • Флаг m заставляет ^ и $ соответствовать границам строк (многострочный режим)
  • Эти флаги независимы и могут комбинироваться: /pattern/sm
  • Используйте [\s\S] или [^] для широкой совместимости вместо . с флагом s
  • Учитывайте разные последовательности переносов строк в разных ОС
  • Используйте нежадные квантификаторы чтобы не захватить слишком много

Для тестирования и отладки regex паттернов, особенно связанных с переносами строк, используйте RegEx Tester для визуализации соответствий и экспериментов с разными комбинациями флагов.