W3docs

Флаги регулярных выражений 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, объединяет флаги через |, и использует как глобальные, так и ограниченные встроенные переключатели.

java— editable, runs on the server

Что следует вынести из запуска:

  • 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 строго чувствительным к регистру — именно такую точность даёт встроенное ограничение области действия.

Связанные темы

Практика

Практика
Вы компилируете шаблон с Pattern.compile('first.*second', Pattern.MULTILINE) и сопоставляете его с текстом 'first line\nsecond line'. Почему совпадение не найдено и какой флаг это исправит?
Вы компилируете шаблон с Pattern.compile('first.*second', Pattern.MULTILINE) и сопоставляете его с текстом 'first line\nsecond line'. Почему совпадение не найдено и какой флаг это исправит?
Was this page helpful?