W3docs

Классы символов в регулярных выражениях Java

Предопределённые и пользовательские классы символов в Java regex — \d, \w, \s, диапазоны, отрицания и пересечения.

Класс символов — это часть регулярного выражения, которая сопоставляется с одним символом из набора допустимых символов. Когда вы пишете \d, [aeiou] или [^0-9], вы используете класс символов. Это наименьший строительный блок почти любого полезного шаблона, и движок java.util.regex предоставляет три вида: готовые сокращения вроде \d, пользовательские наборы в виде [...] и классы с именами на основе Unicode вроде \p{Lower}. Освоив их, вы разберётесь и с остальным синтаксисом регулярных выражений.

В этой главе рассматриваются все три вида — пользовательские классы в квадратных скобках с диапазонами и отрицанием, предопределённые сокращения, операции над множествами (объединение, пересечение, вычитание) и именованные классы Unicode/POSIX — и всё это объединяется в одной запускаемой программе. Если вы новичок в Java regex, сначала изучите введение в regex и синтаксис regex.

Пользовательские классы: скобки, диапазоны и отрицание

Класс в квадратных скобках [...] соответствует любому одному символу, перечисленному внутри. Укажите символы по одному или используйте дефис для обозначения диапазона. Поставьте ^ сразу после открывающей скобки, чтобы отрицать набор — сопоставляться с любым символом, которого нет в списке.

"[abc]"      // matches one 'a', 'b', or 'c'
"[a-z]"      // any one lowercase letter (a range)
"[A-Za-z0-9]"// any letter or digit (three ranges in one class)
"[^aeiou]"   // any single character that is NOT a vowel

Внутри класса большинство метасимволов теряют своё специальное значение, поэтому их редко нужно экранировать. Исключение составляют литеральные ], ^, - и \ — их следует экранировать или размещать так, чтобы они не были поняты неверно (дефис - в начале или конце является литеральным дефисом, а не диапазоном).

java.util.regex.Pattern p = java.util.regex.Pattern.compile("[-+0-9]");
System.out.println(p.matcher("-").find());   // true: leading - is literal
System.out.println(p.matcher("*").find());   // false

Предопределённые классы: сокращения

Java предоставляет сокращения для наиболее часто используемых наборов. Каждая форма в нижнем регистре имеет дополнение в верхнем регистре, которое соответствует всему, чему не соответствует версия в нижнем регистре.

СокращениеСоответствуетЭквивалентный класс
.любой символ, кроме признаков конца строки
\dцифра[0-9]
\Dне цифра[^0-9]
\wсимвол слова[a-zA-Z_0-9]
\Wне символ слова[^a-zA-Z_0-9]
\sпробельный символ[ \t\n\x0B\f\r]
\Sне пробельный символ[^\s]
Внимание
В исходном коде Java сам символ обратной косой черты должен быть экранирован, поэтому regex \d записывается как "\\d" в строковом литерале, а \w становится "\\w". Забыть вторую обратную косую черту — самая распространённая ошибка в Java regex: "\d" даже не скомпилируется.
String digits = "\\d+";          // regex is \d+  (one or more digits)
String word   = "\\w+";          // regex is \w+
"abc123".replaceAll("\\d", "#"); // "abc###"

Отрицание, пересечение и объединение

Класс в квадратных скобках по умолчанию является объединением — укажите [abcxyz] и получите совпадение с любым из шести символов. Java добавляет два оператора для работы с множествами внутри классов. Оператор && формирует пересечение (соответствует только символам, входящим в оба набора), а вложение одного класса в другой позволяет выполнять вычитание.

КонструкцияЗначение
[a-d[m-p]]объединение: ad или mp
[a-z&&[aeiou]]пересечение: строчные буквы, являющиеся гласными
[a-z&&[^aeiou]]вычитание: строчные буквы, которые не являются гласными (согласные)
"[a-z&&[^aeiou]]"  // all lowercase consonants
"[\\p{L}&&[^\\p{Lu}]]" // any letter that is not uppercase

Отрицание с ^ инвертирует весь класс; пересечение с && сужает его. Правильный выбор между ними делает шаблоны читаемыми, вместо того чтобы нагромождать альтернации.

Именованные классы Unicode и POSIX

Для всего, что выходит за рамки ASCII, используйте семейство \p{...}. Эти именованные классы знают о категориях Unicode и группах в стиле POSIX, а \P{...} — их отрицательная форма. Они незаменимы, когда входные данные содержат буквы с диакритическими знаками, не латинские алфавиты, или когда вы просто хотите использовать говорящие имена.

КлассСоответствует
\p{Lower}строчная буква ASCII ([a-z])
\p{Punct}знак пунктуации
\p{Alnum}буква ASCII или цифра
\p{L}любая буква Unicode (с UNICODE_CHARACTER_CLASS)
\p{IsDigit}цифра Unicode
// Make \w, \d, \s honor full Unicode, not just ASCII:
java.util.regex.Pattern uni =
    java.util.regex.Pattern.compile("\\w+", java.util.regex.Pattern.UNICODE_CHARACTER_CLASS);
System.out.println(uni.matcher("café").results().count()); // 1: "café" is one word

Разбор примера: все виды классов на одной строке

Эта программа создаёт небольшой вспомогательный метод count, который сообщает, сколько символов строки-образца совпадает с классом из одного символа. Запуск одной строки через классы цифр, символов слова, пробельных символов, диапазон, отрицание, пересечение, точку и класс POSIX делает взаимосвязи между ними наглядными — и показывает класс, выполняющий реальную работу внутри более широкого шаблона.

java— editable, runs on the server

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

  • \d и [0-9] оба сообщают 13 для этой строки — они полностью эквивалентны для ASCII-ввода. Предопределённый класс — это просто встроенное имя для набора, который вы могли бы записать вручную, поэтому используйте сокращение для удобства чтения.
  • \D и [^0-9] оба сообщают 30 — дополнение 13 цифр в строке из 43 символов (13 + 30 = 43). Сокращение в верхнем регистре и отрицательный класс в квадратных скобках — это два способа записи одного и того же дополнения.
  • [a-z&&[aeiou]] сообщает 3 — только строчные гласные: e в Order, o в cost и i в ship-by. Заглавная O в Order — это буква в верхнем регистре, поэтому пересечение её исключает. Суть: && сужает класс до символов, входящих в оба набора, а не объединяет их, поэтому заглавные гласные не входят.
  • Точка совпала с 43 символами, включая пробелы и знаки пунктуации, поскольку в этой однострочной строке нет признака конца строки, на котором . остановилась бы. Точка — самый широкий из всех классов, именно поэтому её обычно заменяют более узким.
  • Шаблон [A-Z]\d нашёл A7: классы символов используются не только для подсчёта — объединённые в последовательность, они проверяют структуру; здесь — букву, за которой непосредственно следует цифра. \p{Punct} отдельно нашёл 9 знаков пунктуации, демонстрируя, что именованные классы POSIX работают наряду с сокращениями.

Практика

Практика
Какой класс символов в Java regex соответствует одной строчной букве, которая является гласной?
Какой класс символов в Java regex соответствует одной строчной букве, которая является гласной?

Что изучать дальше

Класс символов соответствует одному символу; следующий шаг — управление тем, сколько их вы сопоставляете и что делать с результатом:

  • Квантификаторы regex — добавьте +, *, ? и {n,m}, чтобы класс совпадал с последовательностью символов.
  • Захватывающие группы — оберните класс в (...), чтобы извлечь найденную подстроку.
  • Pattern и Matcher — API, используемый во всех примерах выше, подробно.
  • Флаги regexCASE_INSENSITIVE, UNICODE_CHARACTER_CLASS и другие параметры, изменяющие поведение классов.
Was this page helpful?