Диапазоны и альтернативы. Точная интерпретация «самодельных масок»
Цель: научиться точно читать «маски» из олимпиадных задач, где символы *, ?, |, [] имеют переопределённую автором семантику, и переводить такие маски в стандартные регулярные выражения.
1) Типовые семантики «самодельных масок» (архетипы)
Важно: всегда читайте условие — автор явно задаёт смысл метасимволов. Самые частые варианты:
- Глоб-подобная (как в shell/Windows):
*— любая (в т.ч. пустая) последовательность символов.?— ровно один любой символ.[abc]— один символ из множества; диапазоныa-z; отрицание часто[!abc](иногда[^abc]).|обычно НЕ имеет смысла вне групп; если используется — автор специально оговаривает «альтернацию».
- Маска с ограниченным алфавитом (по условию):
*и?относятся не к «любому символу», а к «любому символу из заданного алфавита» (например, только латиница и цифры).
- «Литеральная» внутри класса:
- Внутри
[...]символы*,|,!,?почти всегда трактуются как обычные символы (если автор не переопределил).
- Внутри
Правило безопасности: пока не доказано иное, считайте, что:
- Снаружи
[]:*/?— подстановки;|— альтернация ТОЛЬКО если это явно написано. - Внутри
[]: мета — это-(диапазон),](закрывает),\(экранирует). Остальное — литералы.
2) Алгоритм перевода маски в регекс
- Зафиксируйте алфавит «любой символ» из условия:
- Любой ASCII:
.(или[\x00-\x7F]). - Только буквы/цифры:
[A-Za-z0-9]. - Только цифры:
[0-9], не\d.
- Любой ASCII:
- Разберите структуру слева направо:
- Обычные буквы — как есть (экранируйте спецсимволы регекса).
- Класс
[...]— переносим в регекс-класс, аккуратно с-/]/\. *→ соответствующий класс со*(или.*),?→ класс с{1}(или.).- Если встречается авторская «альтернация»
X|Y— оберните:^(?:X|Y)$.
- Добавьте якоря
^и$, чтобы проверять всю строку. - Экранируйте спецсимволы регекса вне классов:
. ^ $ * + ? ( ) [ ] { } | \ - При необходимости уточните «жадность» (обычно не требуется для полных матчей).
Шпаргалка подстановок (часто применимые маппинги):
- Маска
*→ Регекс.*или[Алфавит]* - Маска
?→ Регекс.или[Алфавит] - Маска
[a-z0-9]→ Регекс[a-z0-9](идентично) - Маска
[!abc](если так оговорено) → Регекс[^abc]
3) Важные тонкости классов и диапазонов
- Диапазоны включительны:
[a-g]— 7 символов,[A-S]— 19 символов. - Не пишите
[A-z]— в регексах это захватывает лишние символы междуZиa. Всегда[A-Za-z]. -как литерал: ставьте в начале/конце или экранируйте:[-_+],[A-Z\-].- Внутри
[]символы|,*,!,?— литералы (их не нужно экранировать). Экранируйте только-,],\.
4) Практика: целевая маска SC[a-gA-S][*|!?]OL
Условие (типичное чтение):
SC— литералы S и C.[a-gA-S]— один символ из диапазонаa..gИЛИA..S.[*|!?]— один символ из множества {*,|,!,?} (внутри[]— все четыре буквальные).OL— литералы O и L.
Перевод в стандартный регекс (ASCII-семантика):
- Регекс:
^SC[a-gA-S][*|!?]OL$
Комментарии:- Внутри класса
[*|!?]экранирование не нужно:|и*— обычные символы. - С якорями
^и$мы требуем совпадение всей строки.
- Внутри класса
Проверочные примеры:
- Совпадает:
SCa*OL,SCA!OL,SCg?OL,SCS|OL - Не совпадает:
SCZ*OL(Z не в[A-S]),SCaOL(нет символа из[*|!?]),xSCa*OL(лишние символы, если проверяем весь матч)
Комбинаторный размер (по полезной привычке считать):
[a-g]— 7 символов;[A-S]— 19; итого 26.[*|!?]— 4 символа.- Всего строк:
26 × 4 = 104.
5) Ещё три показательных кейса перевода
Кейс 1. Глоб-подобная маска: AB*CD?EF (где * — любая последовательность любых символов, ? — любой символ)
- Регекс:
^AB.*CD.EF$ - Если по условию «любой» — только буквы/цифры:
^AB[A-Za-z0-9]*CD[A-Za-z0-9]EF$
Кейс 2. Маска с альтернативами: FOO|BAR? (автор явно сказал: | — «ИЛИ» между подстроками)
- Регекс:
^(?:FOO|BAR.)$ - Замечание: если бы
|оказался внутри[], он был бы литералом, а не «ИЛИ».
Кейс 3. Отрицательные классы в маске: USER[!0-9][!A-Z]
- Если автор определил
!как отрицание в классе:- Регекс:
^USER[^0-9][^A-Z]$
- Регекс:
- Если нет —
!трактуется как литерал, и маска означает «символ!,0–9илиA–Z»:- Регекс:
^USER[!0-9A-Z]$
Вывод: без явной оговорки про!в условии считать его литералом внутри[].
- Регекс:
6) Диагностика и отладка
- Сначала переводите строго и минимально, не меняя семантики.
- Тестируйте на целевых коротких строках: положительные, отрицательные, граничные.
- Проверяйте «внутри/снаружи
[]»: не перепутайте, где|— альтернация, а где — литерал. - Якоря
^$обязательны, иначе совпадёт подстрока, а не вся строка.
7) Мини‑упражнения (с ответами)
Маска:
ID[0-9][0-9]-*(где*— любая последовательность букв/цифр/подчёркиваний)- Регекс:
^ID[0-9][0-9]-[A-Za-z0-9_]*$
- Регекс:
Маска:
PASS[AEIOU][a-z]*[!?.](где*— только строчные латинские; последний — один из!?.)- Регекс:
^PASS[AEIOU][a-z]*[!?.]$
- Регекс:
Маска:
X(Y|Z)[A-F0-3]?T(автор явно определил скобки и|как альтернацию;?— любой одиночный символ алфавита[A-F0-3])- Регекс:
^X(?:Y|Z)[A-F0-3]T$
- Регекс:
8) Сводка-памятка
- Чётко зафиксируйте алфавит для
*и?. - Внутри
[]|и*— литералы; следите только за-,],\. - Для авторской «альтернации» оборачивайте в
(?: … | … )и якорьте^…$. - Прогоняйте тесты и проверяйте граничные случаи.
Фрагмент корпуса для примеров и тестов
- The quick brown fox jumps over 13 lazy dogs.
- Start_1 middle_text end9
- password PASSword Pa55w0rd GoodPass9
- a____9 A12345 9start1
- name_surname name--surname username_ _username
- abcde9 abcdef ABCDEF1 ABcdefghij1
- HELLOlll IllIlIll safeSAFE2
- abc def abc_def abc-def
- 123456 0000000000 1234567890```
