Регулярные выражения RegEx в Java: примеры и описание работы
Регулярные выражения в языках программирования — мощный, но сложный в освоении инструмент. Потому неудивительно, что многие откладывают его на потом или стараются использовать по минимуму.
Но это лучший способ обработки текстов, а также метод решения задач, которые связаны с поиском, редактированием, заменой текста в файлах. Потому регулярные выражения стоит знать. Сегодня речь пойдет о регулярных выражениях в популярном кроссплатформенном языке Java.
Содержание
Регулярные выражения в Java
Регулярные выражения в Java — это определенные последовательности символов, с помощью которых можно обрабатывать строки текста по специальным синтаксическими шаблонам.
Пример регулярных выражений выглядит так:
String regex=”java”; // шаблон строки ”java”;
String regex=”\\d{3}”; // шаблон строки из трех цифровых символов;
Эта методика позволяет узнать, входит ли определенный символ или их последовательность в строку. Иначе говоря, это методика для обработки строк.
К примеру, она может применяться, если нужно проверить корректность ввода электронной почты. В нем обязательно должен присутствовать символ @, адрес домена, точка после него и доменная зона. То есть система проверяет, чтобы адрес выглядел как «user@gmail.com» (сам адрес без кавычек, разумеется), а не «user.gmail.com» или «user@gmail,com», или даже «user@gmail.com.».
- Matcher — с его помощью строка проверяется по шаблону, что дает возможности найти совпадения в строках, которая подается на вход. Например, в адресе электронной почты.
- Pattern — выдает уже скомпилированную версию регулярного выражения.
- PatternSyntaxException — в рамках этого класса предоставляются непроверяемые исключения. С помощью этого метода можно искать. Подробнее поговорим ниже.
Методы класса Pattern
Класс Java, который называется Pattern — это базовое решение для работы с регулярными выражениями в Java. Именно его используют при подключении RegEx в код программы.
Этот класс можно использовать двумя разными способами (методами). Во-первых, это Pattern.matches(). Он применяется для быстрой проверки текста на соответствие заданному регулярному выражению. Но он проверяет только один текст или строку.
Во-вторых, это Pattern.compile() — скомпилированный экземпляр Pattern. Вот его уже можно использовать несколько раз, чтобы составить регулярное выражение для нескольких текстов.
Например:
String regex=”java”; // шаблон строки ”java”;
String regex=”\\d{3}”; // шаблон строки из трех цифровых символов;
Методы класса Matcher
Еще один класс Java для регулярных выражений — Matcher (java.util.regex.Matcher) — он необходим для поиска нескольких вхождений того или иного набора символов в рамках одного текста, а также применяется для поиска в разных текстах, которые подаются на вход в пределах одного шаблона. В нем есть ряд своих методов, которые используются для работы.
В числе основных отметим такие:
boolean matches(): этот метод возвращает значениеtrueпри совпадении строки с шаблоном;boolean find(): этот метод возвращает значениеtrueпри обнаружении подстроки, которая совпадает с шаблоном, после чего перейдет к ней;int start(): этот метод возвращает значение индекса соответствия;int end(): используя этот метод, можно получить показатели индекса соответствия;String replaceAll(String str): а вот этот метод выводит значение, которое задается подстрокойstrпри изменении основной строки.
А вот так выглядит пример с использованием Pattern и Matcher:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
public static void main (String[] args) {
Pattern pattern1 = Pattern.compile ("[x-z]+");//Поиск будет происходить от x до z включительно.
//Поиск будет происходить только по символам нижнего регистра.
//Чтобы отключить чувствительность к регистру, можно использовать Pattern.CASE_INSENSITIVE.
Matcher matcher1 = pattern1.matcher ("x y z 1 2 3 4 ");
System.out.println (matcher1.find()); //Поиск любого совпадения с шаблоном.
//Выводится значение true, так как в строке есть символы шаблона.
Matcher matcher2 = pattern1.matcher ("X Y Z 1 2 3 4");
System.out.println (matcher2.find()); //Выводится значение false.
//Так как в строке нет символов, подходящих по шаблону.
Pattern pattern2 = Pattern.compile ("[a-zA-Z0-9]");
//Добавляется поиск по символам нижнего и верхнего регистра, а также цифр.
Matcher matcher3 = pattern2.matcher ("A B C D X Y Z a b c d x y z 1 2 3 4");
System.out.println (matcher3.find()); //Выводится значение true
Методы класса PatternSyntaxException
Еще один класс — PatternSyntaxException. Он выводит сообщение о непроверенном исключении, если в синтаксисе регулярного выражения допущена ошибка. Речь идет о некорректных символах в шаблоне, например, об опечатке.
Класс объявляется вот так:
public class PatternSyntaxException extends IllegalArgumentException
В перечне методов класса отметим такие:
getDescription (): метод получает описание ошибок;int getIndex (): этот метод получает индекс ошибки;getMessage (): в этом методе возвращается многострочная строка, которая содержит описание ошибки, индекс, шаблон с ошибкой и даже визуально показывает, где в шаблоне допущена ошибка;getPattern (): этот метод, в свою очередь, получает ошибочный шаблон регулярного выражения.
Пример класса выглядит так:
Live Demo
package com.tutorialspoint;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
public class PatternSyntaxExceptionDemo {
private static String REGEX = "[";
private static String INPUT = "The dog says meow " + "All dogs say meow.";
private static String REPLACE = "cat";
public static void main(String[] args) {
try{
Pattern pattern = Pattern.compile(REGEX);
// get a matcher object
Matcher matcher = pattern.matcher(INPUT);
INPUT = matcher.replaceAll(REPLACE);
} catch(PatternSyntaxException e){
System.out.println("PatternSyntaxException: ");
System.out.println("Description: "+ e.getDescription());
System.out.println("Index: "+ e.getIndex());
System.out.println("Message: "+ e.getMessage());
System.out.println("Pattern: "+ e.getPattern());
}
}
}
Создание регулярных выражений в Java
Для создания регулярного выражения задействуются строки или объекты класса String. Но далеко не каждая строка автоматически может скомпилироваться в регулярное выражение. Она должна быть соответствующим образом написана — с использованием синтаксиса, который определяется в официальных спецификациях Java.
В данном случае речь идет об использовании букв, цифр и метасимволов, которые имеют специальное значение именно в рамках регулярных выражений.
Синтаксис регулярных выражений
Синтаксические конструкции регулярных выражений, как сказано выше, включают буквенные, цифровые и метасимволы.
Среди них:
- Литералы — этим словом называют обычные буквы, которые не имеют иного обозначения. То есть, это стандартный алфавит. Эти символы применяются для поиска — к примеру, если шаблон содержит слово dog, то литералы задействуют для поиска, а в выдаче окажутся результаты, которые начинаются с сочетания букв dog. То есть, там будут и dog, и doghunter.
- Метасимволы. Это, к примеру, квадратные скобки [] и циркумфлекс (). Также иногда их можно называть специальными символами. Например, если написать ( [ dog] ), то система будет искать все, что не включает в себя сочетания букв dog.
Для поиска границ строк, слов и тому подобных данных используются следующие метасимволы:
^— метасимвол начала обрабатываемой строки;$— метасимвол окончания обрабатываемой строки;-— так задается метасимвол, который должен быть вне скобок, причем он должен быть только один;\b— таким образом задается окончание слова;\B— так задается условие, когда слово не закончено;\A— так задается старт ввода;\Z— так задается окончание ввода.
Также можно выбирать определенные классы символов:
\d— любой цифровой символ;\D— любой нецифровой;\s— символ пробела;\S— символ, не имеющий пробела;.— задать один произвольный символ;\w— буквенно-цифровой символ;\W— любой символ, за исключением буквенно-цифрового.
Для задания диапазона можно использовать -, в этом случае регулярное выражение (a-z) будет искать все символы в заданном диапазоне.
В числе других способов использования косой черты отметим:
\n— перенос строки;\\+— экранирование символа, поскольку косая черта используется в качестве спецсимвола. Подробнее об этом поговорим ниже в соответствующем разделе.
Пример самого простого регулярного выражения для проверки адреса электронной почты на правильность выглядит так:
^[A-Z0-9+_.-]+@[A-Z0-9.-]+$
Здесь проверяется вхождение символа @, точки-разделителя и доменной зоны, которые обязательны для электронной почты.
А вот так выглядит более сложный пример, который ищет цифровые символы в строке:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexMatches {
public static void main( String args[] ) {
// Строка для сканирования, чтобы найти шаблон
String str = "Крещение Киевской Руси произошло в 988 году! Не так ли?";
String pattern = "(.*)(\\d+)(.*)";
// Создание Pattern объекта
Pattern r = Pattern.compile(pattern);
// Создание matcher объекта
Matcher m = r.matcher(str);
if (m.find( )) {
System.out.println("Найдено значение: " + m.group(0));
System.out.println("Найдено значение: " + m.group(1));
System.out.println("Найдено значение: " + m.group(2));
}else {
System.out.println("НЕ СОВПАДАЕТ");
}
}
}
На выходе получим следующий результат:
- Найдено значение: Крещение Киевской Руси произошло в 988 году! Не так ли?
- Найдено значение: Крещение Киевской Руси произошло в 98
- Найдено значение: 8
Квантификаторы, жадный, сверхжадный и ленивый режимы
Помимо символов, в регулярных выражениях применяются квантификаторы. Это ограничители, с помощью которых задается частота появления определенного символа или нескольких. Их нужно записывать после самих символов.
Основные квантификаторы:
?— символ не появляется вовсе или же появляется всего раз;-— символа вовсе нет в строке или появляется или он появляется более чем 0 раз;+— символ появляется не менее раза или большее число раз;{n}— символ появляется заданное число раз (n раз);{n,}— символ появляется заданное число раз с условием (n и больше);{n,m}— не меньше n, но не более m раз.
Квантификаторы могут функционировать в одном из трех режимов: жадном, сверхжадном и ленивом. Базовый — жадный режим — именно в нем регулярные выражения работают по умолчанию.
В жадном режиме программа будет искать символы максимальной длины, совпадающие в рамках строки. Проход осуществляется сначала слева направо, а затем справа налево.
Сверхжадный режим функционирует сходным образом, но он не использует обратный проход (когда проверка строки идет справа налево) — так называемый реверсивный поиск. Это в некоторых случаях позволяет ускорить процесс.
Ленивый режим ищет самое короткое вхождение совпадающих символов, которое удовлетворяет всем условиям, заданным в поисковом шаблоне.
Давайте перейдем к примерам.
Вот так выглядит жадный режим:
“A.+a”// Ищет максимальное по длине совпадение в строке.
//Пример жадного квантификатора
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main
{
public static void main(String[] args)
{
Pattern p = Pattern.compile("a+");
Matcher m = p.matcher("aaa");
while (m.find())
System.out.println("Pattern found from " + m.start() +
" to " + (m.end()-1));
}
}
На выходе будет следующее:
Pattern found from 0 to 2
Сверхжадный режим:
"А.++а"?// Работает также как и жадный режим, но не производит реверсивный поиск при захвате строки.
// Пример сверхжадного квантификатора
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main
{
public static void main(String[] args)
{
Pattern p = Pattern.compile("a++");
Matcher m = p.matcher("aaa");
while (m.find())
System.out.println("Pattern found from " + m.start() +
" to " + (m.end()-1));
}
}
На выходе будет следующее:
Pattern found from 0 to 2
Ленивый режим:
“A.+?a”// Ищет самое короткое совпадение.
//Пример ленивого квантификатора
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main
{
public static void main(String[] args)
{
Pattern p = Pattern.compile("g+?");
Matcher m = p.matcher("ggg");
while (m.find())
System.out.println("Pattern found from " + m.start() +
" to " + (m.end()-1));
}
}
Вывод будет таким:
Pattern found from 0 to 0 Pattern found from 1 to 1 Pattern found from 2 to 2
Примеры использования регулярных выражений в Java
В этом разделе мы рассмотрим некоторые примеры, которые помогут понять, как все это работает на деле.
Проверка введенного адреса электронной почты на корректность
Ранее мы упоминали, что один из базовых примеров — проверка адреса электронной почты на валидность и корректность. То есть чтобы стоял символ @, точка и доменная зона.
Вот так эта проверка выглядит в коде:
List emails = new ArrayList();
emails.add("name@gmail.com");
//Неправильный имейл:
emails.add("@gmail.com");
String regex = "^[A-Za-z0-9+_.-]+@(.+)$";
Pattern pattern = Pattern.compile(regex);
for(String email : emails){
Matcher matcher = pattern.matcher(email);
System.out.println(email +" : "+ matcher.matches());
}
Результат:
name@gmail.com : true
@gmail.com : false
Проверка телефонного номера
Это регулярное выражение проверяет валидность номера телефона. Выглядит оно так:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ValidatePhoneNumber {
public static void main(String[] argv) {
String sPhoneNumber = "605-8889999";
// String sPhoneNumber = "605-88899991";
// String sPhoneNumber = "605-888999A";
Pattern pattern = Pattern.compile("\d{3}-\d{7}");
Matcher matcher = pattern.matcher(sPhoneNumber);
if (matcher.matches()) {
System.out.println("Phone Number Valid");
}
else
{
System.out.println("Phone Number must be in the form XXX-XXXXXXX");
}
}
}
Как можно проверить сетевой адрес (IP-адрес) на правильность
А вот класс для определения валидности IP-адреса, записанного в десятичном виде:
private static boolean checkIP(String input) {
return input.matches("((0|1\\d{0,2}|2([0-4][0-9]|5[0-5]))\\.){3}(0|1\\d{0,2}|2([0-4][0-9]|5[0-5]))");
}
Проверка на корректное число открытых и закрытых скобок в строке
По правилам, количество открытых скобок должно совпадать с количеством закрытых, поскольку в ином случае нарушается логика работы. Это проверяется так:
private static boolean checkExpression(String input) {
Pattern pattern = Pattern.compile("\\([\\d+/*-]*\\)");
Matcher matcher = pattern.matcher(input);
do {
input = matcher.replaceAll("");
matcher = pattern.matcher(input);
} while (matcher.find());
return input.matches("[\\d+/*-]*");
}
Извлечение даты из строки
Теперь попробуем извлечь дату из строки. Это делается следующим образом:
private static String[] getDate(String desc) {
int count = 0;
String[] allMatches = new String[2];
Matcher m = Pattern.compile("(0[1-9]|[12][0-9]|3[01])[- /.](0[1-9]|1[012])[- /.](19|20)\\d\\d").matcher(desc);
while (m.find()) {
allMatches[count] = m.group();
count++;
}
return allMatches;
}
Проверка:
public static void main(String[] args) throws Exception{
String[] dates = getDate("coming from the 25/11/2020 to the 30/11/2020");
System.out.println(dates[0]);
System.out.println(dates[1]);
}
Результат:
25/11/2020 30/11/2020
Заключение
Как видим, регулярные выражения Java широко используются и позволяют реализовывать проверки на корректность данных на лету, хотя многие программисты не любят их из-за сложности. Но в умелых руках это мощное средство для поиска данных, работы со строками и так далее.
Также ознакомиться с регулярными выражениями можно в видео:

Сообщить об опечатке
Текст, который будет отправлен нашим редакторам: