Флаги регулярных выражений Java
Управляйте поведением regex в Java с помощью флагов — CASE_INSENSITIVE, MULTILINE, DOTALL, COMMENTS и встроенного синтаксиса (?i).
Флаг изменяет интерпретацию регулярного выражения, не затрагивая само выражение. Одно и то же выражение может сопоставлять текст с учётом или без учёта регистра, обрабатывать строку как одну линию или как множество, а также позволять . пересекать переносы строк или останавливаться на них — всё это определяется флагами. В Java их задают двумя способами: как int-константы, передаваемые в Pattern.compile(pattern, flags), или как встроенные переключатели вида (?i), записанные непосредственно в шаблоне. В этой главе рассматриваются наиболее востребованные флаги и способы их сочетания.
Два способа задать флаг
Каждый флаг имеет константу в классе Pattern. Передайте её вторым аргументом в compile:
Pattern p = Pattern.compile("error", Pattern.CASE_INSENSITIVE);То же поведение доступно внутри шаблона как встроенный модификатор — обычная строка-шаблон может нести собственные флаги без второго аргумента:
Pattern p = Pattern.compile("(?i)error"); // whole pattern, case-insensitive
Pattern q = Pattern.compile("(?i:error) CODE"); // only the group is case-insensitiveВстроенные флаги удобны, когда шаблон передаётся как обычная строка — в конфигурационном файле, столбце базы данных, аннотации — там, где нельзя передать int. Форма с константой нагляднее, когда флаг является частью кода.
Флаги, которые реально используются
| Константа | Встроенный | Эффект |
|---|---|---|
CASE_INSENSITIVE | (?i) | Совпадение ASCII-букв без учёта регистра |
MULTILINE | (?m) | ^ и $ совпадают на каждой границе строки, а не только на концах всей строки |
DOTALL | (?s) | . также совпадает с символами конца строки (s = "single line") |
COMMENTS | (?x) | Игнорировать неэкранированные пробелы и считать # началом комментария |
UNICODE_CASE | (?u) | Заставить CASE_INSENSITIVE учитывать Unicode-буквы, а не только ASCII |
UNICODE_CHARACTER_CLASS | (?U) | Заставить \w, \d, \b следовать правилам Unicode |
LITERAL | — | Воспринимать весь шаблон как обычный текст, без метасимволов |
Распространённый сюрприз: CASE_INSENSITIVE без дополнений учитывает только ASCII. Чтобы сопоставлять буквы с диакритикой или не-латинские буквы без учёта регистра, объедините его с UNICODE_CASE.
Нечувствительность к регистру
По умолчанию regex чувствителен к регистру, поэтому error не совпадёт с ERROR. Добавьте CASE_INSENSITIVE, и оба совпадут:
Pattern.compile("error").matcher("ERROR").find(); // false
Pattern.compile("error", Pattern.CASE_INSENSITIVE).matcher("ERROR").find(); // true
// For non-ASCII letters, add UNICODE_CASE:
Pattern.compile("é", Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE)
.matcher("É").find(); // trueОбработка строк: MULTILINE и DOTALL
Эти два флага независимы и часто путаются. MULTILINE изменяет поведение якорей ^ и $; DOTALL изменяет поведение точки ..
String text = "first line\nsecond line";
// Without MULTILINE, ^ matches only the very start of the input.
Pattern.compile("^second").matcher(text).find(); // false
// With MULTILINE, ^ matches the start of every line.
Pattern.compile("^second", Pattern.MULTILINE).matcher(text).find(); // true
// Without DOTALL, . will not cross the newline.
Pattern.compile("first.*second").matcher(text).find(); // false
// With DOTALL, . matches the newline too.
Pattern.compile("first.*second", Pattern.DOTALL).matcher(text).find(); // trueИспользуйте MULTILINE при построчном сканировании многострочного лога или документа, и DOTALL — когда одно совпадение должно охватывать несколько строк (блок HTML, многострочная запись).
Объединение флагов
Константы флагов являются битовыми масками, поэтому их объединяют побитовым оператором OR |:
int flags = Pattern.MULTILINE | Pattern.CASE_INSENSITIVE | Pattern.DOTALL;
Pattern p = Pattern.compile("^error.*done$", flags);Встроенный эквивалент объединяет буквы: (?ims) задаёт все три. Также можно выключить флаг внутри группы с помощью минуса: (?-i) отключает нечувствительность к регистру для остальной части шаблона.
Читаемые шаблоны с COMMENTS
Флаг COMMENTS (встроенный (?x)) позволяет сложному шаблону «дышать»: неэкранированные пробелы игнорируются, а # начинает комментарий до конца строки. Это превращает нечитаемую однострочную запись в нечто поддерживаемое:
Pattern phone = Pattern.compile("""
\\d{3} # area code
- # separator
\\d{4} # line number
""", Pattern.COMMENTS);
phone.matcher("555-1234").matches(); // trueПоскольку реальные пробелы игнорируются, для буквального пробела используйте \\s, \\ или класс символов [ ].
Практический пример: одно выражение, несколько флагов
Эта программа запускает несколько шаблонов с флагами и без, чтобы наглядно показать, как каждый флаг меняет результат. Она подсчитывает совпадения без учёта регистра, задаёт якори строк с MULTILINE, пересекает переносы строк с DOTALL, объединяет флаги через |, и использует как глобальные, так и ограниченные встроенные переключатели.
Что следует вынести из запуска:
CASE_INSENSITIVEнашёл 2 вхожденияerror(заглавноеERRORи строчноеerror), тогда как шаблон без флага нашёл только 1 — доказательство того, что чувствительность к регистру включена по умолчанию.MULTILINEзаставил^error:.*$совпасть со средней строкой лога и вывелerror: timeout; без флага^и$привязывались бы только к началу и концу всей строки, и эта внутренняя строка никогда бы не совпала.DOTALLпозволилwarn.*infoперепрыгнуть через два встроенных переноса строк и совпасть (true), тогда как тот же шаблон без флага вернулfalse, потому что.по умолчанию останавливается на символе конца строки.- Комбинированный шаблон
MULTILINE | CASE_INSENSITIVEсовпал с^ERRORна строке, которая фактически начинается со строчногоerror:—trueподтверждает, что оба флага применились одновременно из единой битовой маски OR. - Ограниченный
(?i:hello) WORLDсовпал сHELLO WORLD(true), но не сHELLO world(false): группа(?i:...)учла регистр только дляhello, оставив завершающееWORLDстрого чувствительным к регистру — именно такую точность даёт встроенное ограничение области действия.
Связанные темы
- Введение в регулярные выражения Java — как
PatternиMatcherработают вместе. - Pattern и Matcher — классы, использующие приведённые выше флаги.
- Синтаксис regex и Классы символов — метасимволы, которые флаги изменяют.
- Квантификаторы и Группы — где встроенные флаги с ограниченной областью действия, такие как
(?i:...), наиболее полезны.