Регулярные выражения в Java: основы, синтаксис, примеры

0
0

Регулярные выражения в Java – удобный и функциональный инструмент для работы с текстовой информацией. В этой статье вы узнаете, как правильно использовать регулярные выражения для решения прикладных задач: валидации данных, извлечения нужных фрагментов из текста, замены подстрок. Рассмотрим синтаксис regex в Java, режимы работы, примеры кода. Получите готовые решения для оптимизации шаблонов.

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

Регулярные выражения (regex) – это набор символов, описывающих шаблон для поиска в тексте. Они позволяют быстро находить нужные фрагменты данных, проверять соответствие формату, выполнять замены.

Первый regex появился в 1968 году – его реализовал Кен Томпсон для текстового редактора ed в Unix. С тех пор регулярные выражения стали неотъемлемой частью многих языков программирования и утилит обработки текста.

Главные области использования:

  • Валидация данных
  • Парсинг текста
  • Поиск и замена подстрок

Преимущества regex перед обычным кодом – компактность записи и удобство сопоставления сложных шаблонов. Ограничение – высокая сложность понимания для неопытных пользователей.

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

Рассмотрим базовые элементы синтаксиса regex:

  • Литералы – конкретные символы, которые сами обозначают себя. Например, шаблон «test» будет искать в тексте слово «test».
  • Метасимволы – специальные обозначения: ^ – начало строки $ - конец строки . – любой символ
  • Квадратные скобки – классы символов. Например, [abc] означает «a» или «b» или «c». Можно задавать диапазоны, как [a-z].
  • Классы символов с экранированием, например: \d – цифра [0-9] \w – буква, цифра или _
  • Квантификаторы задают количество повторений: ? – 0 или 1 * – 0 и более + – 1 и более {n} – ровно n раз {n,m} – от n до m

Квантификаторы работают в режимах: жадном, ленивом и сверхжадном.

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

В Java реализация regex находится в пакете java.util.regex. Основные классы:

  • Pattern – компилирует regex
  • Matcher – выполняет поиск по шаблону
  • PatternSyntaxException – исключение ошибки
  • MatchResult – результат сопоставления

В Java нужно экранировать специальные символы. Например, чтобы найти пробел, используем \\s:

 String regex = "\\s"; 

Для работы с regex в Java используют 2 класса – Pattern и Matcher:

 Pattern pattern = Pattern.compile("\\s"); // компиляция Matcher matcher = pattern.matcher("text with spaces"); // поиск 

Matcher содержит удобные методы для работы со сравнениями:

  • matches() – полное совпадение всей строки
  • lookingAt() – совпадение с началом строки
  • find() – поиск совпадения в строке
Лес туманным утром

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

Одно из основных применений regex – проверка входных данных на соответствие нужному формату. Рассмотрим примеры.

Проверка email

Валидация email на соответствие стандарту RFC 5322:

 ^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$ 

Шаблон проверяет наличие имени пользователя, символа @, домена и доменной зоны в адресе.

Валидация телефона

Проверка номера для России:

 ^\\+7\\s?\\(?[0-9]{3}\\)?\\s?-?[0-9]{3}-?[0-9]{2}-?[0-9]{2}$ 

А вот шаблон для телефонов США:

 ^\\+?1?\\s?-?\\(?[0-9]{3}\\)?-?[0-9]{3}-?[0-9]{4}$ 
Программистка изучает сложный код

Проверка IP адреса

Валидация IP в десятичном формате:

 ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ 

Подсчет открытых/закрытых скобок

Проверка баланса скобок в строке:

 ^(\\(([^)]*\\))+[^(]*)+$ 

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

Еще одно распространенное применение регулярок – извлечение нужных данных из текста.

Извлечение даты и времени

Получение даты в формате ДД.ММ.ГГГГ:

 \\d{2}\\.\\d{2}\\.\\d{4} 

А вот шаблон для парсинга даты и времени:

 \\d{2}\\.\\d{2}\\.\\d{4}\\s\\d{2}:\\d{2} 

Парсинг HTML и XML

Извлечение содержимого HTML-тега:

 <(\\w+)>(.*?)</\\1> 

Этот шаблон найдет тег, имя тега, текст внутри тега.

Парсинг CSV

Разбор CSV-файла, где разделитель – запятая:

 "([^,\\"]|\\"|\\\\)*"|[^,\\"]* 

Шаблон извлечет значения ячеек, учитывая возможность кавычек внутри полей.

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

Regex удобно применять для замены подстрок в тексте.

Замена одинарных кавычек на двойные

 '[^\']*\' 

Замена пробелов на табуляцию

 \\s 

Транслитерация текста

 [а-яА-ЯЕе]+ 

Этот шаблон найдет все русские буквы для последующей замены.

Замена расширения файлов

 \\.\\w+$ 

Выражение найдет расширение в имени файла.

Удаление тегов из текста

 <\\w+>.*?</\\w+> 

Шаблон удалит HTML-теги из строки.

Перевод даты в нужный формат

 (\\d{2})\\.(\\d{2})\\.(\\d{4}) 

С помощью групп захвата можно извлечь день, месяц и год для форматирования.

Оптимизация regex в Java

Чтобы ускорить работу регулярок в Java, используйте следующие приемы:

  • Комментарии в сложных выражениях
  • Тестирование на разных данных
  • Разбиение длинных шаблонов
  • Флаги CASE_INSENSITIVE, MULTILINE
  • Кеширование скомпилированных Pattern
  • Избегание backtracking
  • Применение атомарных групп
  • Использование нежадного режима

Это основные способы оптимизировать производительность regex и сделать их понятнее.

Работа со строками в Java

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

Класс String

Встроенный класс String содержит методы для работы с regex:

  • split() – разбивает строку по шаблону
  • replaceAll() – замена по регулярному выражению
  • replaceFirst() – замена первого вхождения
 String str = "Hello World"; String[] parts = str.split(" "); // разбиение по пробелу 

Класс StringBuilder

Конкатенация строк через StringBuilder:

 StringBuilder sb = new StringBuilder(); sb.append(str1); sb.append(str2); String result = sb.toString(); 

Форматирование строк

Пример форматирования числа с помощью DecimalFormat:

 double num = 12345.6789; DecimalFormat df = new DecimalFormat("#,###.##"); String formatted = df.format(num); 

Разбиение строки на части

 String lines = "line1\nline2\r\nline3\rline4"; String[] parts = lines.split("\\r?\\n"); 

Разбиение многострочного текста по переносам строк.

Поиск подстроки в строке

 String text = "Hello world"; int index = text.indexOf("world"); 

Метод indexOf() найдет позицию подстроки.

Регулярные выражения в популярных библиотеках

Помимо java.util.regex, существуют другие библиотеки с поддержкой regex.

Jsoup

Популярная Java-библиотека Jsoup позволяет парсить HTML и извлекать данные с помощью CSS-селекторов и регулярных выражений.

 String html = "<p>Sample <b>text</b>.</p>"; Document doc = Jsoup.parse(html); Elements paragraphs = doc.select("p"); String text = paragraphs.text(); // "Sample text." 

Метод text() вернет текстовое содержимое элемента, удалив все теги.

Jackson

Библиотека Jackson предназначена для сериализации JSON в Java-объекты и обратно. Поддерживает фильтрацию полей с помощью регулярных выражений.

 ObjectMapper mapper = new ObjectMapper(); mapper.setFilterProvider(new SimpleFilterProvider() .addFilter("nameFilter", SimpleBeanPropertyFilter.filterOutAllExcept("firstName", "lastName")) ); String json = mapper.writeValueAsString(person); 

Фильтр выведет в JSON только поля firstName и lastName, остальные будут отфильтрованы.

JAXB

JAXB (Java Architecture for XML Binding) выполняет преобразование Java-объектов в XML и обратно. Поддерживает настройку сериализации с помощью аннотаций.

 @XmlRootElement public class Book { @XmlElement private String title; @XmlTransient private String isbn; } 

Аннотация @XmlTransient исключит поле isbn из сериализации в XML.

Apache Commons Lang

Популярная библиотека Apache Commons Lang содержит утилиты для работы со строками с поддержкой регулярных выражений.

 String input = "Hello world"; String substring = StringUtils.substringBetween(input, "Hello", "world"); 

Метод substringBetween извлечет подстроку между двумя строками.

Google Guava

Библиотека Google Guava предоставляет класс CharMatcher для фильтрации символов в строке по регулярному выражению.

 CharMatcher matcher = CharMatcher.anyOf("abc"); String filtered = matcher.removeFrom(input); 

В результате из строки input будут удалены все символы a, b и c.

Регулярные выражения в потоковой обработке данных

Регулярные выражения могут использоваться в потоковой обработке данных, например в Apache Spark.

 JavaRDD<String> lines = spark.read().textFile("access.log"); JavaRDD<String> ips = lines.map(line -> { Pattern pattern = Pattern.compile("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}"); Matcher matcher = pattern.matcher(line); if(matcher.find()) { return matcher.group(); } else { return null; } }); 

Здесь из лог-файла извлекаются IP-адреса с помощью регулярного выражения.

Регулярные выражения в скриптовых языках

Регулярные выражения можно использовать в скриптовых языках, работающих на JVM.

 Groovy def text = "Some sample text" def pattern = ~/[a-z]+/ def matcher = pattern.matcher(text) matcher.find() // true 

Groovy упрощает синтаксис создания шаблона regex.

 Kotlin val regex = "\\d+".toRegex() val match = regex.find("Sample 123 text 456") println(match?.value) // "123" 

В Kotlin для создания регулярки используется метод toRegex().

Регулярные выражения в интеграционном тестировании

Регулярные выражения применяются для проверок ответов веб-сервисов и API в интеграционном тестировании.

 @Test void userRegistration() { Response response = registerUser(user); Pattern pattern = Pattern.compile(" (\\d+)<\\/id>"); Matcher matcher = pattern.matcher(response.getBody()); Assert.assertTrue(matcher.find()); String id = matcher.group(1); // извлечь id пользователя Assert.assertEquals(200, response.getStatus()); } 

Здесь из ответа JSON извлекается id созданного пользователя для последующих проверок.

Регулярные выражения в фреймворках тестирования

Популярные фреймворки тестирования, такие как JUnit и TestNG, предоставляют утверждения для проверки строк на соответствие регулярным выражениям.

 @Test public void emailValidation() { String email = "test@example.com"; assertTrue(email.matches("\\w+@\\w+\\.\\w+")); } 

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

Регулярные выражения в фреймворках веб-разработки

Распространенные фреймворки веб-разработки используют регулярки для валидации данных на стороне сервера.

 Spring public class MyController { @RequestMapping("/user") public User getUser(@RequestParam @Pattern(regexp="[a-zA-Z ]*") String name) { // ... } } 

Аннотация @Pattern в Spring проверит, что параметр соответствует регулярному выражению.

 Jakarta EE Bean Validation public class User { @Pattern(regexp="\\d{3}-\\d{2}-\\d{4}") private String socialSecurityNumber; } 

Jakarta EE позволяет использовать @Pattern для валидации полей объектов.

Регулярные выражения в языках разметки

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

 JavaScript let regex = /^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$/; let result = regex.test(email); 

В JavaScript для создания регулярки используются слэши /regex/.

 PHP $text = "Sample text"; preg_match("/\w+/", $text, $matches)) print_r($matches); // Array ( [0] => Sample ) 

В PHP регулярные выражения задаются в функциях вроде preg_match().

 Python import re pattern = re.compile(r"\w+") print(pattern.search("Sample text").group()) # Sample 

В Python создают объект Pattern из модуля re.