Регулярные выражения в Java: от основ до продвинутого использования
Регулярные выражения (regex) — это мощный инструмент для работы с текстом, позволяющий выполнять поиск, замену и проверку строк по сложным шаблонам. В Java поддержка регулярных выражений реализована через пакет java.util.regex, который предоставляет два основных класса: Pattern (компилирует шаблон) и Matcher (выполняет операции поиска/замены).
В этой статье мы разберем, как эффективно использовать регулярные выражения в Java, начиная с базового синтаксиса и заканчивая реальными примерами из практики разработки.
1. Основы синтаксиса регулярных выражений в Java
Прежде чем переходить к Java-коду, важно освоить основные метасимволы регулярных выражений:
.— любой одиночный символ (кроме перевода строки)\d— любая цифра (0-9)\w— буква, цифра или подчеркивание\s— пробельный символ (пробел, табуляция, новая строка)*— 0 или более повторений предыдущего символа+— 1 или более повторений?— 0 или 1 повторение (делает символ опциональным)^— начало строки$— конец строки[...]— символьный класс (например,[a-z]— все строчные буквы)(...)— группа захвата
Важно: В Java строки с регулярными выражениями требуют двойного экранирования. Например, чтобы использовать \d, в коде пишем "\\d". Это связано с тем, что обратная косая черта сначала обрабатывается компилятором Java, а затем передается движку regex.
2. Классы Pattern и Matcher — основа работы с regex в Java
Базовая схема работы с регулярными выражениями в Java состоит из трех шагов:
- Создание объекта
Patternпутем компиляции строки шаблона - Создание объекта
Matcherпутем вызова методаmatcher()на строке, которую нужно проверить - Выполнение операций — поиск, совпадение, замена
Пример 1: Проверка соответствия всей строки
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class RegexExample {
public static void main(String[] args) {
// Проверка, является ли строка корректным email-адресом
String email = "user@example.com";
String emailPattern = "^[A-Za-z0-9+_.-]+@(.+)$";
Pattern pattern = Pattern.compile(emailPattern);
Matcher matcher = pattern.matcher(email);
if (matcher.matches()) {
System.out.println("Email корректен");
} else {
System.out.println("Email некорректен");
}
}
}
Метод matches() пытается сопоставить шаблон со всей строкой целиком. Если нужно проверить, содержит ли строка совпадение с шаблоном (не обязательно полностью), используется метод find().
Пример 2: Поиск всех вхождений шаблона в строке
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class FindExample {
public static void main(String[] args) {
String text = "Java 8, Java 11, Java 17 — это версии языка Java";
String regex = "Java\\s+\\d+";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
System.out.println("Найдено: " + matcher.group() +
" (позиция: " + matcher.start() + "-" + matcher.end() + ")");
}
}
}
Результат выполнения:
Найдено: Java 8 (позиция: 0-6)
Найдено: Java 11 (позиция: 8-15)
Найдено: Java 17 (позиция: 17-24)
3. Практические примеры: валидация и извлечение данных
Рассмотрим наиболее востребованные сценарии использования регулярных выражений в Java-разработке.
Пример 3: Валидация номера телефона
public class PhoneValidator {
public static boolean isValidPhone(String phone) {
// Формат: +7 (XXX) XXX-XX-XX или 8 (XXX) XXX-XX-XX
String regex = "^(\\+7|8)\\s?\\(?\\d{3}\\)?\\s?\\d{3}\\-?\\d{2}\\-?\\d{2}$";
return Pattern.matches(regex, phone);
}
public static void main(String[] args) {
System.out.println(isValidPhone("+7 (123) 456-78-90")); // true
System.out.println(isValidPhone("8(999)1234567")); // true
System.out.println(isValidPhone("+71234567890")); // true
System.out.println(isValidPhone("123-45-67")); // false
}
}
Пример 4: Извлечение всех URL из текста
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.ArrayList;
import java.util.List;
public class UrlExtractor {
public static List<String> extractUrls(String text) {
String regex = "https?://[\\w./?=&%-]+";
List<String> urls = new ArrayList<>();
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
urls.add(matcher.group());
}
return urls;
}
public static void main(String[] args) {
String text = "Посетите https://pythonlib.ru и http://example.com для обучения";
List<String> urls = extractUrls(text);
urls.forEach(System.out::println);
}
}
Пример 5: Замена с использованием групп захвата
Группы захвата позволяют не только найти, но и переиспользовать части совпадения при замене.
public class RegexReplace {
public static void main(String[] args) {
String text = "Иванов Иван, Петров Петр, Сидоров Сидор";
// Меняем местами фамилию и имя: "Фамилия Имя" → "Имя Фамилия"
String regex = "(\\w+)\\s+(\\w+)";
String replacement = "$2