Тестер регулярных выражений
Напишите шаблон, смотрите, как он совпадает с вашим текстом по мере ввода, и видьте, что именно делает каждый токен. Группы захвата, предпросмотр замены и проверка совместимости с PCRE и Python.
Шаблон
Ваше регулярное выражение
Пишите только тело шаблона — без окружающих слэшей. Всё обновляется по мере ввода.
Меняет только проверку совместимости — сопоставление всегда выполняется движком JavaScript вашего браузера.
Пресеты
Тестовый текст
Текст для сопоставления
Вставьте реальные данные — строку лога, конфиг, выгрузку чата. Ничего не покидает ваш браузер.
символов: 794 · строк: 14
Wespner ops log — node eu-fra-03 Ticket #4821 opened by [email protected], escalated to [email protected]. Billing contact: [email protected] (invoice WX-2026-0917). Panel: https://panel.wespner.eu/server/eu-fra-03/console Mirror: http://mirror.wespner.eu:8080/backups/latest.tar.zst Node IP 185.199.110.153, gateway 10.0.0.1, bad entry 999.1.1.1 in the allowlist. Server UUID 9f2c1a7e-3b44-4d8e-9c21-7a5f0b6e2d13 (instance 550e8400-e29b-41d4-a716-446655440000). Chat export: [12:04] Steve_84: this build is hell to maintain, honestly [12:05] Alex_MC: rotate the panel password and open a shell on the class-4 node [12:06] Steve_84: damn, the ass-end of that config is unreadable [12:07] Notch_Fan: <img src=x onerror=alert(1)> nice try [12:08] Alex_MC: harassment report filed, see /docs/rcon
Группы захвата
Каждое совпадение, с его группами и позициями
Нумерованные группы происходят из обычных ( ). Именованные группы происходят из (?<name>…) и перечислены отдельно.
Введите шаблон, чтобы увидеть совпадения и их группы захвата.
Режим объяснения
Что на самом деле делает каждая часть шаблона
Читайте сверху вниз — именно в таком порядке это читает движок. Отступ показывает вложенность внутри групп.
(?<user>Named capturing group “user”, also group number 1. Refer to it as $<user> in a replacement, or \k<user> in the pattern.[\w.+-]Any single character that is a word character (letter, digit or underscore), “.”, “+” or “-”.+Repeats the previous token one or more times. Greedy: it takes as much as it can, then hands characters back one at a time if the rest of the pattern fails.)Closes the group opened above.@The character “@”, matched literally.(?<domain>Named capturing group “domain”, also group number 2. Refer to it as $<domain> in a replacement, or \k<domain> in the pattern.(?:Non-capturing group: groups tokens together for a quantifier or an alternation without storing what it matched, so it does not consume a group number.[\w-]Any single character that is a word character (letter, digit or underscore) or “-”.+Repeats the previous token one or more times. Greedy: it takes as much as it can, then hands characters back one at a time if the rest of the pattern fails.\.The character “.”, matched literally. The backslash strips any special meaning it would otherwise have.)Closes the group opened above.+Repeats the previous token one or more times. Greedy: it takes as much as it can, then hands characters back one at a time if the rest of the pattern fails.[a-z]Any single character that is anything from “a” to “z”.{2,}Repeats the previous token at least 2 times, with no upper limit. Greedy: it takes as much as it can, then hands characters back one at a time if the rest of the pattern fails.)Closes the group opened above.giFlags: g finds every match instead of stopping at the first; i ignores letter case.Замена
Предпросмотр поиска и замены
Используйте $1, $2 для нумерованных групп, $<name> для именованных, $& для всего совпадения и $$ для буквального знака доллара.
Результат
Введите шаблон, чтобы увидеть предпросмотр замены.
Честная заметка
Эта страница не запускает PCRE или Python
Здесь только один движок регулярных выражений: встроенный в ваш браузер, реализующий диалект JavaScript. Выбор PCRE или Python не переключает движок и не может этого сделать — ни PCRE, ни CPython не работают в этой вкладке.
На самом деле настройка диалекта проверяет ваш шаблон на конструкции, которые пишутся иначе, ведут себя иначе или просто не существуют в выбранном вами диалекте. Относитесь к совпадениям выше как к результатам JavaScript, а к списку справа — как к «что вас укусит, когда вы вставите это в PHP или Python».
Эквивалентный вызов
const re = /(?<user>[\w.+-]+)@(?<domain>(?:[\w-]+\.)+[a-z]{2,})/gi;
for (const m of text.matchAll(re)) console.log(m);A literal is fine when the pattern is fixed. Building one from a variable needs new RegExp(src, flags) — and the source escaped first.
Проверка совместимости
Совместимость с JavaScript
Эвристика — шаблон сканируется как текст, так что конструкция, написанная внутри класса символов, всё равно может быть отмечена.
Шпаргалка
Жадные и ленивые квантификаторы
Самая частая причина, по которой шаблон «совпадает со слишком многим».
<.*> против <b>bold</b> совпадает со всей строкой, а не с <b>. * и + жадные: они захватывают всё, что могут, и отдают символы обратно только когда остальная часть шаблона проваливается.
Добавьте ?, чтобы сделать квантификатор ленивым — <.*?> останавливается на первом >. Обычно ещё лучше: скажите то, что вы на самом деле имеете в виду, <[^>]*>, который вообще не может пересечь разделитель и не откатывается.
Шпаргалка
Якоря и границы
^ и $ — это начало и конец строки, пока вы не добавите флаг m, после чего они становятся началом и концом каждой строки. Забытый m в многострочном конфиг-файле — вот почему построчный шаблон молча ничего не находит.
\b — это нулевой по ширине символ границы слова, а не символ. \bcat\b совпадает с cat, но не с concatenate. Внутри класса символов [\b] означает backspace — настоящая ловушка.
Шаблону, который должен совпадать со всей входной строкой, нужны оба якоря. ^\d+ сам по себе спокойно совпадает с началом 123abc.
Шпаргалка
Катастрофический откат (backtracking)
Вложенные квантификаторы, где внутренняя и внешняя части могут совпадать с одним и тем же текстом — (a+)+$, (\w+\s?)*$, (\d+)*x — дают движку экспоненциально много способов разбить входную строку. На неудачной строке каждый дополнительный символ примерно удваивает работу, так что 30 символов могут занять минуты.
Решение — убрать неоднозначность: (a+)+ превращается в a+; (\w+\s?)* превращается в \w+(?:\s\w+)*. Там, где движок это поддерживает, атомарная группа (?>…) или собственнический квантификатор a++ полностью запрещают откат — они есть в PCRE и Python 3.11+, но их нет в JavaScript.
Этот тестер выполняет сопоставление в Web Worker с ограничением по времени, так что неуправляемый шаблон прерывается, а не замораживает вкладку. У вашего продакшен-сервера такой страховочной сетки нет.
Шпаргалка
Фильтры слов и проблема Scunthorpe
Список слов без границ совпадает и внутри безобидных слов. Канонический пример — английский город Scunthorpe, жителям которого годами блокировали регистрацию в сервисах из-за четырёх букв в середине названия.
Ближе к делу: hell совпадает с shell, ass — с class и password, doc — с document. Обёртывание альтернативы в \b(?:…)\b исправляет большую часть этого. Это не исправит намеренного обхода (h e l l, h3ll), а попытки гнаться за этим с помощью regex создают больше ложных срабатываний, чем предотвращают — поэтому реальная модерация сочетает небольшой консервативный regex с проверкой человеком.
Шпаргалка
Экранирование, классы и точка
Внутри [ ] большинство метасимволов теряют свою силу: [.+*] — это три обычных символа. Особыми остаются только ^ (в первой позиции), - (между символами) и обратная косая черта, а ] нужно экранировать.
Точка означает «любой символ, кроме разрыва строки», пока вы не добавите s. В шаблоне для IP или версии неэкранированная точка совпадает с чем угодно — 1.2.3.4 совпадёт и с 1x2y3z4.
Когда вы строите шаблон из пользовательского ввода, сначала экранируйте его. В JavaScript: s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"). В PHP — preg_quote(), в Python — re.escape().
Шпаргалка
Группы, которые вам, вероятно, стоит сделать незахватывающими
Каждая ( ) сохраняет своё совпадение и перенумеровывает всё, что после неё. Если группировка нужна вам только для альтернативы или квантификатора, используйте (?:…) — это сохраняет ваш $1 стабильным, когда позже вы добавите группу перед ним.
Именованные группы (?<user>…) полностью переживают изменение порядка и гораздо лучше читаются в строке замены: $<user> вместо $3. В Python они пишутся как (?P<user>…).
Управляете собственным игровым сервером?
Игровые серверы Wespner с защитой от DDoS, дисками NVMe и активацией за несколько минут.