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

Последнее обновление: 25.06.2018

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

Некоторые методы класса String принимают регулярные выражения и используют их для выполнения операций над строками.

split

Для разделения строки на подстроки применяется метод 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|,|!|\\." подстрока может соответствовать пробелу, запятой, восклицательному знаку или точке. Причем поскольку точка представляет специальную последовательность, то, чтобы указать, что мы имеем в виду имеено знак точки, а не специальную последовательность, перед точкой ставим слеши.

Соответствие строки. matches

Еще один метод класса 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 цифровых символов.

Класс Pattern

Большая часть функциональности по работе с регулярными выражениями в 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

Рассмотрим основные методы класса 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

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

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850