JavaRush /Blog Java /Random-PL /Wyrażenia regularne w Javie (RegEx)

Wyrażenia regularne w Javie (RegEx)

Opublikowano w grupie Random-PL
Wyrażenia regularne to temat, który programiści, nawet doświadczeni, często odkładają na później. Jednak większość programistów Java prędzej czy później będzie musiała poradzić sobie z przetwarzaniem tekstu. Najczęściej - z operacjami wyszukiwania w tekście i edycji. Bez wyrażeń regularnych produktywny i kompaktowy kod programu związany z przetwarzaniem tekstu jest po prostu nie do pomyślenia. Więc nie odkładaj tego na później, zajmijmy się teraz „stałymi bywalcami”. To nie jest takie trudne zadanie.

Co to jest wyrażenie regularne RegEx?

W rzeczywistości wyrażenie regularne (RegEx w Javie) jest wzorcem wyszukiwania ciągu w tekście. W Javie początkową reprezentacją tego wzorca jest zawsze ciąg znaków, czyli obiekt klasy String. Jednak w wyrażenie regularne nie można skompilować żadnego ciągu znaków, a jedynie taki, który przestrzega zasad pisania wyrażeń regularnych - składnia zdefiniowana w specyfikacji języka. Do napisania wyrażenia regularnego używane są znaki alfabetyczne i numeryczne, a także metaznaki - znaki, które mają specjalne znaczenie w składni wyrażeń regularnych. Na przykład:
String regex = "java"; // szablon napisu "java";
String regex = "\\d{3}"; // szablon napisu składający się z trzech znaków numerycznych;

Tworzenie wyrażeń regularnych w Javie

Aby utworzyć RegEx w Javie, musisz wykonać dwa proste kroki:
  1. zapisz go jako ciąg znaków, używając składni wyrażeń regularnych;
  2. skompiluj ten ciąg do wyrażenia regularnego;
Praca z wyrażeniami regularnymi w dowolnym programie Java rozpoczyna się od utworzenia obiektu klasy Pattern. W tym celu należy wywołać jedną z dwóch metod statycznych dostępnych w klasie compile. Pierwsza metoda przyjmuje jeden argument – ​​literał łańcuchowy wyrażenia regularnego, a druga – plus kolejny parametr, który włącza tryb porównywania szablonu z tekstem:
public static Pattern compile (String literal)
public static Pattern compile (String literal, int flags)
Lista możliwych wartości parametrów flagsjest zdefiniowana w klasie Patterni jest dla nas dostępna jako statyczne zmienne klasy. Na przykład:
Pattern pattern = Pattern.compile("java", Pattern.CASE_INSENSITIVE);//wyszukiwanie dopasowań do wzorca będzie odbywało się bez uwzględniania wielkości liter.
Zasadniczo klasa Patternjest konstruktorem wyrażeń regularnych. W skrócie metoda compilewywołuje prywatnego konstruktora klasy Patternw celu utworzenia skompilowanego widoku. Ta metoda tworzenia instancji szablonu została zaimplementowana w celu utworzenia jej jako niezmiennego obiektu. Podczas tworzenia sprawdzana jest składnia wyrażenia regularnego. Jeżeli w wierszu występują błędy, generowany jest wyjątek PatternSyntaxException.

Składnia wyrażeń regularnych

Składnia wyrażeń regularnych opiera się na użyciu symboli <([{\^-=$!|]})?*+.>, które można łączyć ze znakami alfabetu. W zależności od roli można je podzielić na kilka grup:
1. Metaznaki do dopasowywania granic linii lub tekstu
Metacharakter Zamiar
^ początek linii
$ koniec linii
\B granica słowa
\B nie ma limitu słów
\A początek wprowadzania
\G koniec poprzedniego meczu
\Z koniec wprowadzania
\z koniec wprowadzania
2. Metaznaki do wyszukiwania klas postaci
Metacharakter Zamiar
\D symbol cyfrowy
\D znak nienumeryczny
\S znak kosmiczny
\S znak inny niż biały znak
\w znak alfanumeryczny lub podkreślenie
\W dowolny znak inny niż alfabet, cyfra lub znak podkreślenia
. dowolny znak
3. Metaznaki do wyszukiwania symboli edycji tekstu
Metacharakter Zamiar
\T znak tabulacji
\N znak nowej linii
\R znak powrotu karetki
\F przejdź do nowej strony
\u0085 znak następnego wiersza
\u 2028 znak separatora linii
\u 2029 symbol separatora akapitu
4. Metaznaki do grupowania znaków
Metacharakter Zamiar
[a BC] dowolne z powyższych (a, b lub c)
[^abc] inne niż wymienione (nie a, b, c)
[a-zA-Z] łączenie zakresów (wielkość liter alfabetu łacińskiego od a do z nie uwzględnia wielkości liter)
[reklama[mp]] łączenie znaków (a do d i m do p)
[az&&[def]] przecięcie symboli (symbole d,e,f)
[az&&[^bc]] odejmowanie znaków (znaki a, dz)
5. Metasymbole oznaczające liczbę znaków – kwantyfikatory. Kwantyfikator zawsze pojawia się po znaku lub grupie znaków.
Metacharakter Zamiar
? jeden lub nieobecny
* zero lub więcej razy
+ jeden lub więcej razy
{N} n razy
{N,} n razy lub więcej
{n, m} nie mniej niż n razy i nie więcej niż m razy

Tryb zachłannego kwantyfikatora

Cechą szczególną kwantyfikatorów jest możliwość wykorzystania ich w różnych trybach: zachłannym, superchciwym i leniwym. Tryb ekstra zachłanny włącza się poprzez dodanie symbolu „ +” po kwantyfikatorze, a tryb leniwy poprzez dodanie symbolu „ ?„. Na przykład:
„A.+a” // tryb chciwy
"A.++a" // tryb nadmiernej chciwości
"A.+?a" // tryb leniwy
Używając tego szablonu jako przykładu, spróbujmy zrozumieć, jak kwantyfikatory działają w różnych trybach. Domyślnie kwantyfikator działa w trybie zachłannym. Oznacza to, że szuka najdłuższego możliwego dopasowania w ciągu. W wyniku uruchomienia tego kodu:
public static void main(String[] args) {
    String text = „Egor Alla Aleksander”;
    Pattern pattern = Pattern.compile(„A.+a”);
    Matcher matcher = pattern.matcher(text);
    while (matcher.find()) {
        System.out.println(text.substring(matcher.start(), matcher.end()));
    }
}
otrzymamy następujący wynik: Alla Alexa Algorytm wyszukiwania dla danego wzorca „ А.+а” wykonywany jest w następującej kolejności:
  1. W podanym wzorze pierwszym znakiem jest znak rosyjskiej litery А. Matcherdopasowuje go do każdego znaku tekstu, zaczynając od pozycji zero. Na pozycji zerowej w naszym tekście znajduje się symbol Е, czyli Matcherprzechodzi on sekwencyjnie przez znaki w tekście, aż natrafi na dopasowanie do wzorca. W naszym przykładzie jest to symbol na pozycji nr 5.

    Wyrażenia regularne w Javie - 2
  2. Po znalezieniu dopasowania z pierwszym znakiem wzorca Matchersprawdza dopasowanie z drugim znakiem wzorca. W naszym przypadku jest to symbol „ .”, który oznacza dowolny znak.

    Wyrażenia regularne w Javie - 3

    Na szóstej pozycji znajduje się symbol litery л. Oczywiście pasuje do wzorca „dowolny znak”.

  3. Matcherprzechodzi do sprawdzania kolejnego znaku ze wzorca. W naszym szablonie jest to określone za pomocą .+kwantyfikatora „ ”. Ponieważ liczba powtórzeń „dowolnego znaku” we wzorcu jest jedno lub więcej razy, Matcherpobiera po kolei kolejny znak z ciągu i sprawdza go pod kątem zgodności ze wzorcem, o ile spełniony jest warunek „dowolny znak”, w naszym przykładzie - do końca wiersza (od pozycji nr 7 - nr 18 tekstu).

    Wyrażenia regularne w Javie - 4

    Właściwie Matcherchwyta całą linię do końca - tutaj objawia się jego „chciwość”.

  4. Po Matcherdotarciu do końca tekstu i zakończeniu sprawdzania „ А.+” części wzorca, Matcher rozpoczyna sprawdzanie reszty wzorca – znaku litery а. Ponieważ tekst w kierunku do przodu się skończył, sprawdzenie odbywa się w kierunku odwrotnym, zaczynając od ostatniego znaku:

    Wyrażenia regularne w Javie - 5
  5. Matcher„pamięta” liczbę powtórzeń we wzorcu „ .+”, przy której dotarł do końca tekstu, więc zmniejsza liczbę powtórzeń o jeden i sprawdza wzorzec pod kątem tekstu, aż znajdzie dopasowanie: Wyrażenia regularne w Javie - 6

Ultra-chciwy tryb kwantyfikatora

W trybie super-chciwym mechanizm dopasowujący działa podobnie do mechanizmu trybu zachłannego. Różnica polega na tym, że gdy dojdziesz do końca wiersza, nie będzie można szukać wstecz. Oznacza to, że pierwsze trzy etapy trybu super zachłannego będą podobne do trybu zachłannego. Po przechwyceniu całego ciągu, moduł dopasowujący dodaje resztę wzorca i porównuje ją z przechwyconym ciągiem. W naszym przykładzie, podczas wykonywania głównej metody ze wzorcem „ А.++а”, nie zostaną znalezione żadne dopasowania. Wyrażenia regularne w Javie - 7

Tryb leniwego kwantyfikatora

  1. W tym trybie na początkowym etapie, podobnie jak w trybie zachłannym, szukane jest dopasowanie z pierwszym znakiem wzorca:

    Wyrażenia regularne w Javie - 8
  2. Następnie szuka dopasowania z kolejnym znakiem we wzorcu – dowolnym znakiem:

    Wyrażenia regularne w Javie - 9
  3. W przeciwieństwie do trybu zachłannego, tryb leniwy wyszukuje w tekście najkrótsze dopasowanie, więc po znalezieniu dopasowania z drugim znakiem wzorca, który jest określony kropką i pasuje do znaku znajdującego się na pozycji nr 6 tekstu, Matchersprawdzi, czy tekst pasuje do reszty wzorca - znaku „ а” .

    Wyrażenia regularne w Javie - 10
  4. Ponieważ nie znaleziono zgodności ze wzorcem w tekście (na pozycji nr 7 w tekście znajduje się symbol „” л), Matcherdodaje do wzorca kolejny „dowolny znak”, ponieważ jest on określony jedno lub więcej razy, i ponownie porównuje wzór z tekstem na pozycjach od nr 5 do nr 8:

    Wyrażenia regularne w Javie - 11
  5. W naszym przypadku znaleziono dopasowanie, ale koniec tekstu nie został jeszcze osiągnięty. Dlatego od pozycji nr 9 sprawdzanie rozpoczyna się od wyszukania pierwszego znaku wzorca przy użyciu podobnego algorytmu, a następnie powtarza się aż do końca tekstu.

    Wyrażenia regularne w Javie - 12
W wyniku tej metody, mainkorzystając z А.+?аszablonu „ ”, otrzymamy następujący wynik: Alla Alexa Jak widać z naszego przykładu, używając różnych trybów kwantyfikatora dla tego samego szablonu, otrzymaliśmy różne wyniki. Dlatego należy wziąć pod uwagę tę funkcję i wybrać żądany tryb w zależności od pożądanego wyniku podczas wyszukiwania.

Uciekanie znaków w wyrażeniach regularnych

Ponieważ wyrażenie regularne w Javie, a dokładniej jego początkowa reprezentacja, jest określane za pomocą literału łańcuchowego, konieczne jest uwzględnienie reguł specyfikacji Java dotyczących literałów łańcuchowych. W szczególności ukośnik odwrotny „ \” w literałach łańcuchowych w kodzie źródłowym Java jest interpretowany jako znak ucieczki, który ostrzega kompilator, że znak, który po nim następuje, jest znakiem specjalnym i należy go interpretować w specjalny sposób. Na przykład:
String s = "The root directory is \nWindows";//zawiń Windows do nowej linii
String s = "The root directory is \u00A7Windows";//wstaw znak akapitu przed Windows
Dlatego w literałach łańcuchowych opisujących wyrażenie regularne i używających \znaku „ ” (na przykład w przypadku metaznaków) należy go podwoić , aby kompilator kodu bajtowego Java nie zinterpretował go inaczej. Na przykład:
String regex = "\\s"; // szablon do wyszukiwania spacji
String regex = "\"Windows\""; // wzorzec wyszukiwania ciągu „Windows”
Podwójnego ukośnika odwrotnego należy także używać do ucieczki od znaków specjalnych, jeśli planujemy używać ich jako „zwykłych” znaków. Na przykład:
String regex = "How\\?"; // szablon wyszukiwania ciągu znaków „Jak?”

Metody klasy Pattern

Klasa Patternposiada inne metody pracy z wyrażeniami regularnymi: String pattern()– zwraca oryginalną ciąg znaków reprezentujący wyrażenie regularne, z którego utworzono obiekt Pattern:
Pattern pattern = Pattern.compile("abc");
System.out.println(Pattern.pattern())//"abc"
static boolean matches(String regex, CharSequence input)– umożliwia sprawdzenie wyrażenia regularnego przekazanego w parametrze regex z tekstem przekazanym w parametrze input. Zwraca: true – jeśli tekst pasuje do wzorca; fałsz – inaczej; Przykład:
System.out.println(Pattern.matches(„A.+a”,„Alla”));//true
System.out.println(Pattern.matches(„A.+a”,„Egor Alla Aleksander”));//false
int flags()– zwraca flagswartości parametrów szablonu, które zostały ustawione podczas jego tworzenia, lub 0, jeśli ten parametr nie został ustawiony. Przykład:
Pattern pattern = Pattern.compile("abc");
System.out.println(pattern.flags());// 0
Pattern pattern = Pattern.compile("abc",Pattern.CASE_INSENSITIVE);
System.out.println(pattern.flags());// 2
String[] split(CharSequence text, int limit)– dzieli tekst przekazany jako parametr na tablicę elementów String. Parametr limitokreśla maksymalną liczbę dopasowań, jakie są wyszukiwane w tekście:
  • kiedy – następuje limit>0wyszukiwanie dopasowań;limit-1
  • at limit<0– wyszukuje wszystkie dopasowania w tekście
  • kiedy limit=0– wyszukuje wszystkie dopasowania w tekście, pomijając puste linie na końcu tablicy;
Przykład:
public static void main(String[] args) {
    String text = „Egor Alla Anna”;
    Pattern pattern = Pattern.compile("\\s");
    String[] strings = pattern.split(text,2);
    for (String s : strings) {
        System.out.println(s);
    }
    System.out.println("---------");
    String[] strings1 = pattern.split(text);
    for (String s : strings1) {
        System.out.println(s);
    }
}
Dane wyjściowe konsoli: Egor Alla Anna -------- Egor Alla AnnaMatcher Poniżej rozważymy inną metodę klasową tworzenia obiektu .

Metody klasy Matcher

Matcherto klasa, z której tworzony jest obiekt do wyszukiwania wzorców. Matcher– to jest „wyszukiwarka”, „silnik” wyrażeń regularnych. Aby przeprowadzić wyszukiwanie, musi otrzymać dwie rzeczy: wzór wyszukiwania i „adres”, pod którym ma szukać. Aby utworzyć obiekt, Matcherw klasie udostępniana jest następująca metoda Pattern: рublic Matcher matcher(CharSequence input) Jako argument metoda przyjmuje ciąg znaków, w jakim będzie wykonywane wyszukiwanie. Są to obiekty klas implementujących interfejs CharSequence. Możesz przekazać nie tylko String, ale także StringBuffer, i jako argument . Szablon wyszukiwania to obiekt klasy , na którym wywoływana jest metoda . Przykład tworzenia matchera: StringBuilderSegmentCharBufferPatternmatcher
Pattern p = Pattern.compile("a*b");// skompilował wyrażenie regularne do widoku
Matcher m = p.matcher("aaaaab");//utworzył wyszukiwarkę w tekście „aaaaab” używając wzorca „a*b”
Teraz za pomocą naszej „wyszukiwarki” możemy wyszukiwać dopasowania, sprawdzać położenie dopasowania w tekście i zastępować tekst metodami klasowymi. Metoda boolean find()wyszukuje w tekście kolejne dopasowanie do wzorca. Stosując tę ​​metodę i operator pętli można analizować cały tekst według modelu zdarzenia (wykonywać niezbędne operacje w momencie wystąpienia zdarzenia - znalezienie dopasowania w tekście). Na przykład, korzystając z metod tej klasy, int start()można int end()określić pozycje dopasowań w tekście, a za pomocą metod String replaceFirst(String replacement)zastąpić String replaceAll(String replacement)dopasowania w tekście innym tekstem zastępczym. Przykład:
public static void main(String[] args) {
    String text = „Egor Alla Anna”;
    Pattern pattern = Pattern.compile("A.+?a");

    Matcher matcher = pattern.matcher(text);
    while (matcher.find()) {
        int start=matcher.start();
        int end=matcher.end();
        System.out.println("Znaleziono dopasowanie" + text.substring(start,end) + " с "+ start + " Przez " + (end-1) + "pozycja");
    }
    System.out.println(matcher.replaceFirst(„Ira”));
    System.out.println(matcher.replaceAll(„Olga”));
    System.out.println(text);
}
Wynik programu: Znaleziono dopasowanie Alla od 5 do 8 pozycji Znaleziono dopasowanie Anna od 10 do 13 pozycji Egor Ira Anna Egor Olga Olga Egor Alla Anna Z przykładu widać, że metody replaceFirsttworzą replaceAllnowy obiekt String- ciąg znaków, który to tekst źródłowy, w którym dopasowania do szablonu są zastępowane tekstem przekazywanym do metody jako argument. Co więcej, metoda replaceFirstzastępuje tylko pierwsze dopasowanie i replaceAllwszystkie dopasowania w teście. Tekst oryginalny pozostaje niezmieniony. Zastosowanie innych metod klas Matcher, a także przykłady wyrażeń regularnych można znaleźć w tej serii artykułów . Najczęstsze operacje na wyrażeniach regularnych podczas pracy z tekstem pochodzą z klas Patterni Matchersą wbudowane w String. Są to metody takie jak split, matches, replaceFirst, replaceAll. Ale tak naprawdę „pod maską” używają Patterni Matcher. Dlatego jeśli chcesz zamienić tekst lub porównać ciągi w programie bez pisania niepotrzebnego kodu, użyj metod klasy String. Jeśli potrzebujesz zaawansowanych możliwości, pomyśl o klasach Patterni plikach Matcher.

Wniosek

Wyrażenie regularne jest opisywane w programie Java przy użyciu ciągów znaków pasujących do wzorca zdefiniowanego przez reguły. Po uruchomieniu kodu Java rekompiluje ten ciąg znaków do obiektu klasy Patterni używa obiektu klasy Matcherdo wyszukiwania dopasowań w tekście. Jak wspomniałem na początku, wyrażenia regularne bardzo często odkładane są na później, uznane za trudny temat. Jeśli jednak zrozumiesz podstawy składni, metaznaków, ucieczki i przestudiujesz przykłady wyrażeń regularnych, okażą się one znacznie prostsze, niż się wydaje na pierwszy rzut oka.
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION