Регулярные выражения представляют мощный инструмент для обработки строк. Регулярные выражения позволяют задать шаблон, которому должна соответствовать строка или подстрока.
Некоторые методы класса String принимают регулярные выражения и используют их для выполнения операций над строками.
Для разделения строки на подстроки применяется метод split(). В качестве параметра он может принимать регулярное выражение, которое представляет критерий разделения строки.
Например, разделим предложение на слова:
String text = "FIFA will never regret it"; String[] words = text.split("\\s*(\\s|,|!|\\.)\\s*"); for(String word : words){ System.out.println(word); }
Для разделения применяется регулярное выражение "\\s*(\\s|,|!|\\.)\\s*". Подвыражние "\\s" по сути представляет пробел. Звездочка указывает, что символ может присутствовать от 0 до бесконечного количества раз. То есть добавляем звездочку и мы получаем неопределенное количество идущих подряд пробелов - "\\s*" (то есть неважно, сколько пробелов между словами). Причем пробелы может вообще не быть. В скобках указывает группа выражений, которая может идти после неопределенного количества пробелов. Группа позволяет нам определить набо значений через вертикальную черту, и подстрока должна соответствовать одному из этих значений. То есть в группе "\\s|,|!|\\." подстрока может соответствовать пробелу, запятой, восклицательному знаку или точке. Причем поскольку точка представляет специальную последовательность, то, чтобы указать, что мы имеем в виду имеено знак точки, а не специальную последовательность, перед точкой ставим слеши.
Еще один метод класса String - matches() принимает регулярное выражение и возвращает true, если строка соответствует этому выражению. Иначе возвращает false.
Например, проверим, соответствует ли строка номеру телефона:
String input = "+12343454556"; boolean result = input.matches("(\\+*)\\d{11}"); if(result){ System.out.println("It is a phone number"); } else{ System.out.println("It is not a phone number!"); }
В данном случае в регулярном выражение сначала определяется группа "(\\+*)". То есть вначале может идти знак плюса, но также он может отсутствовать. Далее смотрим, соответствуют ли последующие 11 символов цифрам. Выражение "\\d" представляет цифровой символ, а число в фигурных скобках - {11} - сколько раз данный тип символов должен повторяться. То есть мы ищем строку, где вначале может идти знак плюс (или он может отсутствовать), а потом идет 11 цифровых символов.
Большая часть функциональности по работе с регулярными выражениями в Java сосредоточена в пакете java.util.regex.
Само регулярное выражение представляет шаблон для поиска совпадений в строке. Для задания подобного шаблона и поиска подстрок в строке, которые удовлетворяют данному шаблону, в Java определены классы Pattern и Matcher.
Для простого поиска соответствий в классе Pattern определен статический метод boolean matches(String pattern, CharSequence input). Данный метод возвращает true, если последовательность символов input полностью соответствует шаблону строки pattern:
import java.util.regex.Pattern; public class StringsApp { public static void main(String[] args) { String input = "Hello"; boolean found = Pattern.matches("Hello", input); if(found) System.out.println("Найдено"); else System.out.println("Не найдено"); } }
Но, как правило, для поиска соответствий применяется другой способ - использование класса Matcher.
Рассмотрим основные методы класса Matcher:
boolean matches(): возвращает true, если вся строка совпадает с шаблоном
boolean find(): возвращает true, если в строке есть подстрока, которая совпадает с шаблоном, и переходит к этой подстроке
String group(): возвращает подстроку, которая совпала с шаблоном в результате вызова метода find.
Если совпадение отсутствует, то метод генерирует исключение IllegalStateException
.
int start(): возвращает индекс текущего совпадения
int end(): возвращает индекс следующего совпадения после текущего
String replaceAll(String str): заменяет все найденные совпадения подстрокой str и возвращает измененную строку с учетом замен
Используем класс Matcher. Для этого вначале надо создать объект Pattern с помощью статического метода compile(), который позволяет установить шаблон:
Pattern pattern = Pattern.compile("Hello");
В качестве шаблона выступает строка "Hello". Метод compile()
возвращает объект Pattern, который мы затем можем использовать в программе.
В классе Pattern также определен метод matcher(String input), который в качестве параметра принимает строку, где надо проводить поиск, и возвращает объект Matcher:
String input = "Hello world! Hello Java!"; Pattern pattern = Pattern.compile("hello"); Matcher matcher = pattern.matcher(input);
Затем у объекта Matcher вызывается метод matches() для поиска соответствий шаблону в тексте:
import java.util.regex.Matcher; import java.util.regex.Pattern; public class StringsApp { public static void main(String[] args) { String input = "Hello"; Pattern pattern = Pattern.compile("Hello"); Matcher matcher = pattern.matcher(input); boolean found = matcher.matches(); if(found) System.out.println("Найдено"); else System.out.println("Не найдено"); } }
Рассмотрим более функциональный пример с нахождением не полного соответствия, а отдельных совпадений в строке:
import java.util.regex.Matcher; import java.util.regex.Pattern; public class StringsApp { public static void main(String[] args) { String input = "Hello Java! Hello JavaScript! JavaSE 8."; Pattern pattern = Pattern.compile("Java(\\w*)"); Matcher matcher = pattern.matcher(input); while(matcher.find()) System.out.println(matcher.group()); } }
Допустим, мы хотим найти в строке все вхождения слова Java. В исходной строке это три слова: "Java", "JavaScript" и "JavaSE". Для этого применим шаблон "Java(\\w*)". Данный шаблон использует синтаксис регулярных выражений. Слово "Java" в начале говорит о том, что все совпадения в строке должны начинаться на Java. Выражение (\\w*) означает, что после "Java" в совпадении может находиться любое количество алфавитно-цифровых символов. Выражение \w означает алфавитно-цифровой символ, а звездочка после выражения указывает на неопределенное их количество - их может быть один, два, три или вообще не быть. И чтобы java не рассматривала \w как эскейп-последовательность, как \n, то выражение экранируется еще одним слешем.
Далее применяется метод find()
класса Matcher, который позволяет переходить к следующему совпадению в строке. То есть первый вызов
этого метода найдет первое совпадение в строке, второй вызов найдет второе совпадение и т.д. То есть с помощью цикла while(matcher.find())
мы можем пройтись по всем совпадениям. Каждое совпадение мы можем получить с помощью метода matcher.group()
. В итоге
программа выдаст следующий результат:
Java JavaScript JavaSE
Теперь сделаем замену всех совпадений с помощью метода replaceAll()
:
String input = "Hello Java! Hello JavaScript! JavaSE 8."; Pattern pattern = Pattern.compile("Java(\\w*)"); Matcher matcher = pattern.matcher(input); String newStr = matcher.replaceAll("HTML"); System.out.println(newStr); // Hello HTML! Hello HTML! HTML 8.
Также надо отметить, что в классе String также имеется метод replaceAll()
с подобным действием:
String input = "Hello Java! Hello JavaScript! JavaSE 8."; String myStr =input.replaceAll("Java(\\w*)", "HTML"); System.out.println(myStr); // Hello HTML! Hello HTML! HTML 8.
С помощью метода String[] split(CharSequence input) класса Pattern можно разделить строку на массив подстрок по определенному разделителю. Например, мы хотим выделить из строки отдельные слова:
import java.util.regex.Pattern; public class StringsApp { public static void main(String[] args) { String input = "Hello Java! Hello JavaScript! JavaSE 8."; Pattern pattern = Pattern.compile("[ ,.!?]"); String[] words = pattern.split(input); for(String word:words) System.out.println(word); } }
И консоль выведет набор слов:
Hello Java Hello JavaScript JavaSE 8
При этом все символы-разделители удаляются. Однако, данный способ разбивки не идеален: у нас остаются некоторые пробелы, которые расцениваются как лексемы, а не как разделители. Для более точной и изощренной разбивки нам следует применять элементы регулярных выражений. Так, заменим шаблон на следующий:
Pattern pattern = Pattern.compile("\\s*(\\s|,|!|\\.)\\s*");
Теперь у нас останутся только слова:
Hello Java Hello JavaScript JavaSE 8
Далее мы подробнее рассмотрим синтаксис регулярных выражений и из каких элементов мы можем создавать шаблоны.