Найти тему
Сам себе джавист

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

Оглавление

Java regex - это официальный API регулярных выражений Java. Термин Java regex - это сокращение от Java regular expression. API регулярных выражений Java находится в пакете java.util.regex, который является частью стандартной Java (JSE) начиная с Java 1.4. В этом руководстве по регулярным выражениям Java будет объяснено, как использовать этот API для сопоставления регулярных выражений с текстом.

Хотя регулярные выражения Java являются частью стандартной Java начиная с Java 1.4, в этом руководстве по регулярным выражениям Java рассматривается Java regex API, выпущенный с Java 8.

Регулярные выражения

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

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

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

Далее на этой странице я покажу вам несколько примеров того, как сопоставлять регулярные выражения с текстом с помощью Java regex API. Но сначала я представлю основные классы Java regex API в следующем разделе.

Основные классы регулярных выражений Java

Java regex API состоит из двух основных классов. Это:

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

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

Оба класса Pattern и Matcher подробно описаны в их документации. Смотрите ссылки выше этого руководства по регулярным выражениям Java.

Пример регулярных выражений Java

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

Пример шаблона

Вот простой пример регулярного выражения java, который использует регулярное выражение для проверки, содержит ли текст подстроку 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 содержит регулярное выражение в виде строки. Регулярное выражение соответствует всем текстам, содержащим один или несколько символов (.*), за которым следует текст http://, за которым следует один или несколько символов (.*).

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

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

Пример сопоставления

Вот еще один пример регулярных выражений Java, который использует класс 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. С помощью этого экземпляра сопоставления пример находит все вхождения регулярного выражения в тексте.

Синтаксис регулярных выражений Java

Ключевым аспектом регулярных выражений является их синтаксис. Java - не единственный язык программирования, который поддерживает регулярные выражения. Их поддерживает большинство современных языков программирования. Однако синтаксис, используемый в каждом языке для определения регулярных выражений, не совсем одинаков. Поэтому вам нужно будет изучить синтаксис, используемый вашим языком программирования.

В следующих разделах этого руководства по регулярным выражениям Java я приведу вам примеры их синтаксиса, чтобы вы начали работу с Java regex API и регулярными выражениями в целом. Синтаксис регулярных выражений, используемый Java regex API, подробно описан в документации о синтаксисе регулярных выражений Java

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

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

String regex = "http://";

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

String text1 = "http://";

Но не это:

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

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

Метасимволы

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

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

Что именно означают эти метасимволы, будет объяснено далее в этом руководстве по регулярным выражениям Java. Просто имейте в виду, что если вы включите, например, "." (fullstop) в регулярное выражение, оно не будет соответствовать символу fullstop, а будет соответствовать чему-то другому, определяемому этим метасимволом (также объяснено позже).

Экранирующие символы

Как упоминалось выше, метасимволы в регулярных выражениях Java имеют особое значение. Если вы действительно хотите сопоставить эти символы в их буквальной форме, а не в их метасимвольном значении, вы должны "экранировать" метасимвол, который вы хотите сопоставить. Чтобы экранировать метасимвол, вы используете экранирующий символ регулярного выражения Java - символ обратной косой черты. Экранирование символа означает, что перед ним стоит символ обратной косой черты. Например, вот так:

\.

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

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

String regex = "\\.";

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

\.

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

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

String regex = "\\.";

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

String regex = "\\\\";

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

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

До сих пор мы видели только, как сопоставлять определенные символы, такие как "h", "t", "p" и т.д. Однако вы также можете просто сопоставить любой символ, независимо от того, что это за символ. Синтаксис регулярных выражений Java позволяет вам сделать это с помощью "." символ (точка). Вот пример регулярного выражения, которое соответствует любому символу:

String regex = ".";

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

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

String regex = "H.llo";

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

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

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

String regex = "H[ae]llo";

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

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

Вы можете сопоставить диапазон символов, указав первый и последний символ в диапазоне с тире между ними. Например, класс символов [a-z] будет соответствовать всем символам между строчными буквами 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".

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

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

String regex = "[a-z]";

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

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

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

Сопоставление цифр

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

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

String regex = "Hi\\d";

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

Сопоставление нецифровых символов

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

String regex = "Hi\\D";

Это регулярное выражение будет соответствовать любой строке, начинающейся с "Hi", за которой следует один символ, который не является цифрой.

Сопоставление букв

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

String regex = "Hi\\w";

Это регулярное выражение будет соответствовать любой строке, начинающейся с "Hi", за которой следует символ одного слова.

Сопоставление Символов, не являющихся словами

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

Вот пример регулярного выражения с использованием класса символов, отличного от слов:

String regex = "Hi\\W";

границы

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

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

Некоторые из этих граничных сопоставителей объясняются ниже.

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

Сопоставитель ^ соответствует началу строки в соответствии со спецификацией Java API. Однако на практике кажется, что он соответствует только началу строки. Например, в следующем примере получено только одно совпадение с индексом 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 соответствует границе слова, что означает местоположение во входной строке, где слово либо начинается, либо заканчивается.

Вот пример границы слова регулярного выражения Java:

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 - с двумя символами \\ (обратная косая черта). Причина этого объясняется в разделе об экранировании символов. Компилятор Java использует \ в качестве escape-символа и, таким образом, требует двух символов обратной косой черты друг за другом, чтобы вставить один символ обратной косой черты в строку.

Результатом выполнения этого примера будет:

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.

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

Сопоставитель границ \B соответствует границам, не являющимся словами. Граница, не состоящая из слов, - это граница между двумя символами, которые оба являются частью одного и того же слова. Другими словами, комбинация символов не является последовательностью символов от слова к слову (которая является границей слова). Вот простой пример сопоставления границ регулярных выражений Java без слов:

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. Здесь я представлю некоторые из наиболее часто используемых кванторов.

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

String regex = "Hello*";

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

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

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

String regex = "Hell\\+";

Это регулярное выражение будет соответствовать строке "Hell+".;

Вы также можете сопоставить точное количество определенного символа с помощью квантора {n}, где n - количество символов, которые вы хотите сопоставить. Вот пример:

String regex = "Hello{2}";

Это регулярное выражение будет соответствовать строке "Helloo" (с двумя символами o в конце).

Вы можете установить верхнюю и нижнюю границы количества символов, которые вы хотите сопоставить, например:

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

Это регулярное выражение будет соответствовать строкам "Helloo", "Hellooo" и "Helloooo". Другими словами, строка "Ад" с 2, 3 или 4 символами o в конце.

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

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

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

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, а затем ноль или более символов. Строка соответствует этим критериям.

Оператор or является явным и представлен символом канала |. Вот пример регулярного выражения, содержащего два подвыражения с логическим оператором or между ними:

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()

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

Вот пример matches():

String text = "one two three two one";
boolean matches = text.matches(".*two.*");

split()

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

Вот пример split():

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

В этом примере будут возвращены три строки "one", "three" и "one".

replaceFirst()

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

Вот пример replaceFirst():

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

В этом примере будет возвращена строка "one five three two one".

replaceAll()

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

Вот пример replaceAll():

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

В этом примере будет возвращена строка "one five three five one".