Статьи

Учебник по регулярным выражениям Java с примерами

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

Что такое регулярные выражения?

Регулярное выражение определяет шаблон для String. Регулярные выражения могут использоваться для поиска, редактирования или манипулирования текстом. Регулярные выражения не зависят от языка, но они немного отличаются для каждого языка. Регулярные выражения Java больше всего похожи на Perl.

Классы Java Regular Expression представлены в пакете java.util.regex , который содержит три класса: Pattern , Matcher и PatternSyntaxException .

1. Объект Pattern — это скомпилированная версия регулярного выражения. У него нет открытого конструктора, и мы используем его открытый статический метод compile для создания объекта шаблона путем передачи аргумента регулярного выражения.

2. Matcher — это объект механизма регулярных выражений, который сопоставляет входной шаблон String с созданным объектом шаблона. Этот класс не имеет общедоступного конструктора, и мы получаем объект Matcher, используя метод сопоставления объектов-шаблонов, который принимает входную строку в качестве аргумента. Затем мы используем метод совпадений, который возвращает логический результат на основе входной строки, совпадает с шаблоном регулярного выражения или нет.

3. PatternSyntaxException генерируется, если синтаксис регулярного выражения неверен.

Давайте посмотрим на все эти классы в действии на простом примере:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
package com.journaldev.util;
 
import java.util.regex.*;
 
public class PatternExample {
 
    public static void main(String[] args) {
        Pattern pattern = Pattern.compile('.xx.');
        Matcher matcher = pattern.matcher('MxxY');
        System.out.println('Input String matches regex - '+matcher.matches());
        // bad regular expression
        pattern = Pattern.compile('*xx*');
 
    }
 
}

Вывод вышеуказанной программы:

01
02
03
04
05
06
07
08
09
10
11
Input String matches regex - true
Exception in thread 'main' java.util.regex.PatternSyntaxException: Dangling meta character '*' near index 0
*xx*
^
    at java.util.regex.Pattern.error(Pattern.java:1924)
    at java.util.regex.Pattern.sequence(Pattern.java:2090)
    at java.util.regex.Pattern.expr(Pattern.java:1964)
    at java.util.regex.Pattern.compile(Pattern.java:1665)
    at java.util.regex.Pattern.(Pattern.java:1337)
    at java.util.regex.Pattern.compile(Pattern.java:1022)
    at com.journaldev.util.PatternExample.main(PatternExample.java:13)

Поскольку регулярные выражения вращаются вокруг String, класс Java String был расширен в Java 1.4 для предоставления метода совпадений, который выполняет сопоставление с образцом. Внутренне он использует классы Pattern и Matcher для выполнения обработки, но, очевидно, сокращает количество строк кода.

Класс Pattern также содержит метод совпадений, который принимает регулярное выражение и вводит String в качестве аргумента и возвращает логический результат после сопоставления с ними.

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

1
2
3
String str = 'bbb';
System.out.println('Using String matches method: '+str.matches('.bb'));
System.out.println('Using Pattern matches method: '+Pattern.matches('.bb', str));

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

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

Например, регулярное выражение «121» будет совпадать с «31212142121» только дважды как «_121____121».

Регулярные выражения общие совпадающие символы

Регулярное выражение Описание пример
, Соответствует любому одному знаку, включает в себя все («..», «a%») — правда («..», «.a») — правда

(«..», «а») — неверно

^ ххх Соответствует регулярному выражению xxx в начале строки («^ Ac», «abcd») — правда («^ a», «a») — правда

(«^ A», «ac») — неверно

ххх $ Соответствует регулярному выражению xxx в конце строки («..Cd $», «abcd») — true («a $», «a») — true

(«A $», «aca») — ложь

[ABC] Может соответствовать любой букве a, b или c. [] известны как классы персонажей. («^ [Abc] d.», «Ad9 ″) — true (« [ab] .d $ »,« bad ») — true

(«[Ab] x», «cx») — неверно

[ABC] [12] Может соответствовать a, b или c, а затем 1 или 2 («[Ab] [12].», «A2 #») — true («[ab] .. [12]«, «acd2 ″) — true

(«[Ab] [12]«, «c2») — неверно

[^ А] Когда ^ — первый символ в [], он отрицает шаблон, соответствует чему-либо, кроме a, b или c («[^ Ab] [^ 12].», «C3 #») — правда («[^ ab] .. [^ 12]«, «xcd3 ″) — правда»

(«[^ Ab] [^ 12]«, «c2») — неверно

[А-e1-8] Соответствует диапазонам от a до e или от 1 до 8 («[A-e1-3].», «D #») — правда («[a-e1-3]«, «2 ″) — правда

(«[A-e1-3]», «f2 ″) — неверно

хх | уу Соответствует регулярному выражению xx или yy («X. | Y», «xa») — правда («x. | Y», «y») — правда

(«X. | Y», «yz») — неверно

Метасимволы регулярных выражений Java

Регулярное выражение Описание
\ d Любые цифры, кроме [0-9]
\ D Любая не цифра, сокращение от [^ 0-9]
\ s Любой символ пробела, сокращение от [\ t \ n \ x0B \ f \ r]
\ S Любой непробельный символ, сокращение от [^ \ s]
\ ш Любой символ слова, сокращение от [a-zA-Z_0-9]
\ W Любой несловесный символ, сокращение от [^ \ w]
\ б Граница слова
\ B Граница без слов

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

  1. Перед метасимволом ставьте обратную косую черту (\).
  2. Храните metacharcter в пределах \ Q (который начинает кавычку) и \ E (который заканчивает его).

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

Квантификаторы определяют количество вхождений символа для сопоставления.

Регулярное выражение Описание
Икс? х происходит один раз или не происходит вообще
ИКС* X встречается ноль или более раз
X + X встречается один или несколько раз
Х {п} X встречается ровно n раз
Х {п,} X встречается n или более раз
Х {п, т} X встречается как минимум n раз, но не более m раз

Квантификаторы также можно использовать с классами символов и группами захвата.

Например, [abc] + означает a, b или c один или несколько раз.

(abc) + означает группу «abc» еще один раз. Мы сейчас поговорим о Capturing Group .

Группы захвата регулярных выражений

Группы захвата используются для обработки нескольких символов как единой единицы. Вы можете создать группу, используя () . Часть входной строки, соответствующая группе захвата, сохраняется в памяти и может быть вызвана с помощью метода Backreference .

Вы можете использовать метод matcher.groupCount, чтобы узнать количество групп захвата в шаблоне регулярных выражений. Например, в ((a) (bc)) содержится 3 группы захвата; ((a) (bc)), (a) и (bc).

Вы можете использовать Backreference в регулярном выражении с обратной косой чертой (\) и затем номером группы, которую нужно вызвать.

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

1
2
3
4
System.out.println(Pattern.matches('(\\w\\d)\\1', 'a2a2')); //true
System.out.println(Pattern.matches('(\\w\\d)\\1', 'a2b2')); //false
System.out.println(Pattern.matches('(AB)(B\\d)\\2\\1', 'ABB2B2AB')); //true
System.out.println(Pattern.matches('(AB)(B\\d)\\2\\1', 'ABB2B3AB')); //false

В первом примере во время выполнения первой группой захвата является (\ w \ d), которая оценивается как «a2» при сопоставлении со входной строкой «a2a2» и сохраняется в памяти. Таким образом, \ 1 ссылается на «a2» и, следовательно, возвращает true. По той же причине второе утверждение печатается как ложное.
Попробуйте понять этот сценарий для утверждений 3 и 4 самостоятельно.

Теперь рассмотрим некоторые важные методы классов Pattern и Matcher.

Мы можем создать объект Pattern с флагами. Например шаблон. CASE_INSENSITIVE включает сопоставление без учета регистра.

Класс Pattern также предоставляет split (String), который похож на метод split () класса String.
Метод класса класса toString () возвращает регулярное выражение String, из которого был скомпилирован этот шаблон.

Классы соответствия имеют методы индекса start () и end (), которые точно показывают, где совпадение было найдено во входной строке.

Класс Matcher также предоставляет методы манипуляции с String replaceAll (замена String) и replaceFirst (замена String) .

Теперь мы увидим эти общие функции в действии через простой класс Java:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package com.journaldev.util;
 
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
public class RegexExamples {
 
    public static void main(String[] args) {
        // using pattern with flags
        Pattern pattern = Pattern.compile('ab', Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher('ABcabdAb');
        // using Matcher find(), group(), start() and end() methods
        while (matcher.find()) {
            System.out.println('Found the text \'' + matcher.group()
                    + '\' starting at ' + matcher.start()
                    + ' index and ending at index ' + matcher.end());
        }
 
        // using Pattern split() method
        pattern = Pattern.compile('\\W');
        String[] words = pattern.split('one@two#three:four$five');
        for (String s : words) {
            System.out.println('Split using Pattern.split(): ' + s);
        }
 
        // using Matcher.replaceFirst() and replaceAll() methods
        pattern = Pattern.compile('1*2');
        matcher = pattern.matcher('11234512678');
        System.out.println('Using replaceAll: ' + matcher.replaceAll('_'));
        System.out.println('Using replaceFirst: ' + matcher.replaceFirst('_'));
    }
 
}

Вывод вышеуказанной программы:

01
02
03
04
05
06
07
08
09
10
Found the text 'AB' starting at 0 index and ending at index 2
Found the text 'ab' starting at 3 index and ending at index 5
Found the text 'Ab' starting at 6 index and ending at index 8
Split using Pattern.split(): one
Split using Pattern.split(): two
Split using Pattern.split(): three
Split using Pattern.split(): four
Split using Pattern.split(): five
Using replaceAll: _345_678
Using replaceFirst: _34512678

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

Ссылка: учебник по регулярным выражениям Java с примерами от нашего партнера по JCG Панкаджа Кумара в блоге Developer Recipes .