Java Regex — регулярные выражения

Java Regex является официальным API регулярных выражений Java. Находится в пакете java.util.regex, который является частью стандартной  JSE начиная с версии 1.4.

Регулярное выражение — это текстовый шаблон, используемый для поиска в тексте. Вы делаете это путем «сопоставления» его с текстом. Результат:

  • Значение true / false, указывающее соответствует ли регулярное выражение тексту.
  • Набор совпадений — одно совпадение для каждого вхождения, найденного в тексте.

Например, вы можете использовать регулярное выражение для поиска в строке адресов электронной почты, URL-адресов, телефонных номеров, дат и т. д. Это можно сделать путем сопоставления различных выражений со строкой. Результатом сопоставления каждого из них будет набор совпадений — один набор совпадений для каждого выражения (может совпадать более одного раза).

Java Regex Core Classes

Состоит из двух основных классов:

  • Шаблон (java.util.regex.Pattern)
  • Соответствия (java.util.regex.Matcher)

Класс Pattern используется для создания шаблонов. Шаблон — это предварительно скомпилированное регулярное выражение в форме объекта (как экземпляр шаблона), способное сопоставляться с текстом.

Класс Matcher используется для сопоставления заданного экземпляра Pattern с текстом несколько раз. Другими словами, искать несколько вхождений в тексте. Matcher скажет вам, где в тексте (индекс символа) он нашел вхождения. Вы можете получить экземпляр Matcher из экземпляра Pattern.

Пример Pattern

Вот простой пример, чтобы проверить, содержит ли текст подстроку http: //:

String text    =
        "This is the text to be searched " +
        "for occurrences of the http:// pattern.";

String regex = ".*http://.*";

boolean matches = Pattern.matches(regex, text);

System.out.println("matches = " + matches);

Текстовая переменная содержит текст для проверки с помощью регулярного выражения.

Переменная pattern содержит выражение в виде String. Оно соответствует всем текстам, содержащим один или несколько символов (. *), за которыми следует текст http: //, а за ним следует один или несколько символов (. *).

В третьей строке используется статический метод Pattern.matches(), чтобы проверить, соответствует ли шаблон тексту. Если да, то Pattern.matches() возвращает true. Если нет, false.

В этом примере фактически не проверяется, является ли найденная строка http: // частью действительного URL с именем домена и суффиксом (.com, .net и т. д.).

Пример Matcher

Используем класс Matcher для поиска нескольких вхождений подстроки «is» внутри текста:

String text    =
        "This is the text which is to be searched " +
        "for occurrences of the word 'is'.";

String regex = "is";

Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(text);

int count = 0;
while(matcher.find()) {
    count++;
    System.out.println("found: " + count + " : "
            + matcher.start() + " - " + matcher.end());
}

Из экземпляра Pattern получается экземпляр Matcher. С помощью него пример находит все вхождения регулярного выражения в тексте.

Синтаксис

Сопоставление символов

Первое, на что нужно обратить внимание — как написать регулярное выражение, которое сопоставляет символы с заданным текстом. Например, выражение, определенное здесь:

String regex = "http://";

будет соответствовать всем строкам, которые точно соответствуют ему. Не может быть символов до или после http: // — или выражение не будет соответствовать тексту. Например, приведенный выше синтаксис будет соответствовать этому тексту:

String text1 = "http://";

Но не этот текст:

String text2 = "The URL is: http://mydomain.com";

Вторая строка содержит символы как до, так и после http: //, с которым сопоставляется.

Метасимволы

Метасимволы — это символы в выражении, которые интерпретируются как имеющие специальные значения. Эти метасимволы:

< > ( ) [
] { } \ ^
= $ ! |
? * + .

Если вы включите, например, «.» (Fullstop) в выражение, оно не будет соответствовать символу fullstop, но будет соответствовать чему-то еще, что определено этим метасимволом.

Экранирование метасимволов

Если вы действительно хотите сопоставить эти символы в их буквальной форме, а не в значении метасимвола, вы должны «экранировать» метасимвол, которому хотите соответствовать. Для этого вы используете escape-символ — символ обратной косой черты. Выход из символа означает предшествующий ему символ обратной косой черты. Например, вот так:

\.

В этом примере. символу предшествует (экранированный) символ \. После экранирования символ полной остановки будет фактически соответствовать символу полной остановки во входном тексте. Особое значение метасимвола для экранированного метасимвола игнорируется — используется только его фактическое буквальное значение (например, точка полного останова).

Синтаксис использует символ обратной косой черты в качестве escape-символа, как это делают строки. Это немного затрудняет написание выражения в строке. Посмотрите на этот пример:

String regex = "\\.";

Обратите внимание, что выражение String содержит две обратные косые черты друг за другом, а затем .

Причина в том, что сначала компилятор интерпретирует два \\ символа как экранированный символ Java String. После завершения компиляции остается только один \, поскольку \\ означает символ \. Таким образом, строка выглядит так:

\.

Теперь включается интерпретатор выражений и интерпретирует оставшуюся обратную косую черту как escape-символ. Следующий персонаж. теперь интерпретируется как фактическая полная остановка, а не специальное регулярное выражение, означающее, что оно имеет иное значение. Таким образом, оставшееся выражение соответствует символу полной остановки и ничего более.

Несколько символов имеют особое значение в синтаксисе. Если вы хотите сопоставить этот явный символ и не использовать его с его специальным значением, вам нужно сначала экранировать его с помощью символа обратной косой черты. Например, чтобы соответствовать символу полной остановки, вам нужно написать:

String regex = "\\.";

Чтобы соответствовать самому символу обратной косой черты, вам нужно написать:

String regex = "\\\\";

Получить экранирование символов в выражениях может быть сложно.

Соответствие любому символу

Вы можете просто сопоставить любой символ, независимо от того, какой он. Синтаксис позволяет делать это, используя. символ (точка / полная остановка). Вот пример:

String regex = ".";

Это выражение соответствует одному символу, независимо от того, какой это символ.

. символ может быть объединен с другими для создания более сложных выражений:

String regex = "H.llo";

Это регулярное выражение будет соответствовать любой строке Java, которая содержит символы «H», за которыми следует любой символ, за которым следуют символы «llo». Таким образом, это регулярное выражение будет соответствовать всем строкам «Hello», «Hallo», «Hullo», «Hxllo» и т. Д.

Соответствие любому из набора символов

Поддерживается сопоставление любого из указанного набора символов, используя так называемые классы символов. Вот пример класса символов:

String regex = "H[ae]llo";

Класс символов (набор символов для сопоставления) заключен в квадратные скобки — другими словами, часть выражения [ae]. Квадратные скобки не совпадают — только символы внутри них.

Класс символов будет соответствовать одному из вложенных символов независимо от того, какой, но не более одного. Таким образом, приведенное выше выражение будет соответствовать любой из двух строк «Hallo» или «Hello», но никаких других строк. Только «а» или «е» допускается между «Н» и «llo».

Вы можете сопоставить диапазон символов, указав первый и последний символ в диапазоне с тире между ними. Например, класс символов [az] будет соответствовать всем символам между строчными буквами a и строчными буквами z, включая a и z.

Вы можете иметь более одного диапазона символов в пределах класса символов. Например, класс символов [a-zA-Z] будет соответствовать всем буквам между a и z или между A и Z.

Вы также можете использовать диапазоны для цифр. Например, класс символов [0-9] будет соответствовать символам от 0 до 9, включая оба.

Если вы действительно хотите сопоставить одну из квадратных скобок в тексте, вам нужно будет их избежать. Вот как выглядят экранирующие квадратные скобки:

String regex = "H\\[llo";

\\ [является левой квадратной скобкой Это выражение будет соответствовать строке «H [llo».

Если вы хотите сопоставить квадратные скобки внутри класса символов, вот как это выглядит:

String regex = "H[\\[\\]]llo";

Класс символов — это часть: [\\ [\\]]. Он содержит две квадратных скобки(\\ [и \\]). Будет соответствовать строкам «H [llo» и «H] llo».

Соответствие диапазону символов

Можно указать диапазон символов для сопоставления. Задать диапазон символов проще, чем явно указать каждый символ для сопоставления. Например, вы можете сопоставить символы от a до z следующим образом:

String regex = "[a-z]";

Это выражение будет соответствовать любому отдельному символу от a до z в алфавите.

Классы символов чувствительны к регистру. Чтобы сопоставить все символы от a до z независимо от регистра, вы должны включить как прописные, так и строчные диапазоны:

String regex = "[a-zA-Z]";

Соответствующие цифры

Вы можете сопоставить цифры номера с предопределенным классом символов с помощью кода \ d. Класс символов цифр соответствует классу символов [0-9].

Поскольку символ \ также является escape-символом, вам нужно две обратные косые черты в строке, чтобы получить \ d в выражении:

String regex = "Hi\\d";

Это регулярное выражение будет соответствовать строкам, начинающимся с «Hi», за которым следует цифра (от 0 до 9). Таким образом, он будет соответствовать строке «Hi5», но не строке «Hip».

Соответствие не цифр

Совпадение не цифр может быть сделано с помощью предопределенного класса символов [\ D] (заглавная D):

String regex = "Hi\\D";

Будет соответствовать любой строке, которая начинается с «Hi», за которым следует один символ, который не является цифрой.

Соответствующие слова

Вы можете сопоставить символы слова с предопределенным классом символов с кодом \ w. Слово символьный класс соответствует классу символов [a-zA-Z_0-9].

String regex = "Hi\\w";

Будет соответствовать любой строке, которая начинается с «Hi», за которым следует символ одного слова.

Соответствующие несловесные символы

Вы можете сопоставить несловесные символы с предопределенным классом символов [\ W] (заглавными буквами W). Поскольку символ \ также является escape-символом, вам нужно две обратные косые черты в строке, чтобы получить \ w:

String regex = "Hi\\W";

Границы

Java Regex API также может соответствовать границам в строке, а именно началом или концом строки, началом слова и т. д. API Java Regex поддерживает следующие границы:

Символ Описание
^ Начало строки
$ Конец строки
\b Граница слова (где слово начинается или заканчивается, например, пробел, табуляция и т. д.).
\B Несловесная граница
\A Начало ввода.
\G Конец предыдущего совпадения
\Z Конец ввода, кроме конечного объекта (если есть)
\z

Начало строки

Соответствие границ ^ соответствует началу строки в соответствии со спецификацией API Java. Например, следующий пример получает только одно совпадение с индексом 0:

String text = "Line 1\nLine2\nLine3";

Pattern pattern = Pattern.compile("^");
Matcher matcher = pattern.matcher(text);

while(matcher.find()){
    System.out.println("Found match at: "  + matcher.start() + " to " + matcher.end());
}

Даже если входная строка содержит несколько разрывов строк, символ ^ соответствует только началу входной строки, а не началу каждой строки (после каждого переноса строки).

Начало соответствия строки / строки часто используется в сочетании с другими символами, чтобы проверить, начинается ли строка с определенной подстроки. Например, этот пример проверяет, начинается ли строка ввода с подстроки http: //:

String text = "http://jenkov.com";

Pattern pattern = Pattern.compile("^http://");
Matcher matcher = pattern.matcher(text);

while(matcher.find()){
    System.out.println("Found match at: "  + matcher.start() + " to " + matcher.end());
}

В этом примере найдено одно совпадение подстроки http: // из индекса 0 в индекс 7 во входном потоке. Даже если бы входная строка содержала больше экземпляров подстроки http: //, они не соответствовали бы этому регулярному выражению, так как оно начиналось с символа ^.

Конец строки

Соответствие $ соответствует концу строки в соответствии со спецификацией Java. На практике, однако, похоже, что он соответствует только концу входной строки.

Соответствие начала строки часто используется в сочетании с другими символами, чаще всего для проверки, заканчивается ли строка определенной подстрокой:

String text = "http://jenkov.com";

Pattern pattern = Pattern.compile(".com$");
Matcher matcher = pattern.matcher(text);

while(matcher.find()){
    System.out.println("Found match at: "  + matcher.start() + " to " + matcher.end());
}

В этом примере будет найдено одно совпадение в конце входной строки.

Границы слова

Сопоставитель границ \ b соответствует границе слова, что означает местоположение во входной строке, где слово либо начинается, либо заканчивается:

String text = "Mary had a little lamb";

Pattern pattern = Pattern.compile("\\b");
Matcher matcher = pattern.matcher(text);

while(matcher.find()){
    System.out.println("Found match at: "  + matcher.start() + " to " + matcher.end());
}

Этот пример соответствует всем границам слов, найденным во входной строке.

Обратите внимание, как сопоставитель границ слова записывается как \\ b — с двумя символами \\ (обратная косая черта). Причина этого объясняется в разделе об экранировании символов.

Found match at: 0 to 0
Found match at: 4 to 4
Found match at: 5 to 5
Found match at: 8 to 8
Found match at: 9 to 9
Found match at: 10 to 10
Found match at: 11 to 11
Found match at: 17 to 17
Found match at: 18 to 18
Found match at: 22 to 22

В выводе перечислены все места, где слово либо начинается, либо заканчивается во входной строке. Как видите, индексы начала слова указывают на первый символ слова, тогда как окончания слова указывают на первый символ после слова.

String text = "Mary had a little lamb";

Pattern pattern = Pattern.compile("\\bl");
Matcher matcher = pattern.matcher(text);

while(matcher.find()){
    System.out.println("Found match at: "  + matcher.start() + " to " + matcher.end());
}

В этом примере будут найдены все места, где слово начинается с буквы l (строчные буквы). Фактически он также найдет концы этих совпадений, что означает последний символ шаблона, который является строчной буквой l.

Несловесные границы

String text = "Mary had a little lamb";

Pattern pattern = Pattern.compile("\\B");
Matcher matcher = pattern.matcher(text);

while(matcher.find()){
    System.out.println("Found match at: "  + matcher.start() + " to " + matcher.end());
}
Found match at: 1 to 1
Found match at: 2 to 2
Found match at: 3 to 3
Found match at: 6 to 6
Found match at: 7 to 7
Found match at: 12 to 12
Found match at: 13 to 13
Found match at: 14 to 14
Found match at: 15 to 15
Found match at: 16 to 16
Found match at: 19 to 19
Found match at: 20 to 20
Found match at: 21 to 21

Обратите внимание, что эти индексы соответствия соответствуют границам между символами в одном и том же слове.

Квантификаторы

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

String regex = "Hello*";

Это регулярное выражение сопоставляет строки с текстом «Hell», за которым следует ноль или более символов. Таким образом, регулярное выражение будет соответствовать «Hell», «Hello», «Helloo» и т. д.

Если бы квантификатором был символ + вместо символа *, строка должна была бы заканчиваться 1 или более символами o.

String regex = "Hell\\+";

Будет соответствовать строке «Hell+»;

String regex = "Hello{2}";

Будет соответствовать строке «Helloo»(с двумя символами o в конце).

String regex = "Hello{2,4}";

Будет соответствовать строкам «Helloo», «Hellooo» и «Helloooo». Другими словами, строка «Hell» с 2, 3 или 4 символами в конце.

Логические Операторы

Java Regex API поддерживает набор логических операторов, которые можно использовать для объединения нескольких подшаблонов в одном регулярном выражении, а именно оператор and и оператор or.

String text = "Cindarella and Sleeping Beauty sat in a tree";

Pattern pattern = Pattern.compile("[Cc][Ii].*");
Matcher matcher = pattern.matcher(text);

System.out.println("matcher.matches() = " + matcher.matches());

Обратите внимание на 3 подшаблона [Cc], [Ii] и. *

Поскольку в регулярном выражении между этими подшаблонами нет символов, между ними неявно существует оператор and. Это означает, что целевая строка должна соответствовать всем 3 подшаблонам в данном порядке, чтобы соответствовать регулярному выражению в целом. Как видно из строки, выражение соответствует строке. Строка должна начинаться с заглавной или строчной буквы C, за которой следует заглавная или строчная буква I, а затем ноль или более символов. Строка соответствует этим критериям.

String text = "Cindarella and Sleeping Beauty sat in a tree";

Pattern pattern = Pattern.compile(".*Ariel.*|.*Sleeping Beauty.*");
Matcher matcher = pattern.matcher(text);

System.out.println("matcher.matches() = " + matcher.matches());

Как вы можете видеть, шаблон будет соответствовать либо подчиненному шаблону Ariel, либо подчиненному шаблону Sleeping Beauty где-то в целевой строке. Поскольку целевая строка содержит текст «Sleeping Beauty», выражение соответствует целевой строке.

Методы выражений Java String

Класс Java String также имеет несколько методов регулярных выражений.

matches()

Метод принимает регулярное выражение в качестве параметра и возвращает true, если соответствует строке, и false, если нет.

String text = "one two three two one";

boolean matches = text.matches(".*two.*");

split()

Метод разбивает строку на N подстрок и возвращает массив String с этими подстроками. Принимает регулярное выражение в качестве параметра и разбивает строку на все позиции в строке, где выражение соответствует части строки. Выражение не возвращается как часть возвращаемых подстрок.

String text = "one two three two one";

String[] twos = text.split("two");

Этот пример вернет три строки: «один», «три» и «один».

replaceFirst()

Метод возвращает новую строку с первым совпадением регулярного выражения, переданного в качестве первого параметра, со строковым значением второго параметра.

String text = "one two three two one";

String s = text.replaceFirst("two", "five");

Этот пример вернет строку «один пять три два один».

replaceAll()

Метод возвращает новую строку со всеми совпадениями регулярного выражения, переданного в качестве первого параметра, со строковым значением второго параметра.

String text = "one two three two one";

String t = text.replaceAll("two", "five");

Оцените статью