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:- zapisz go jako ciąg znaków, używając składni wyrażeń regularnych;
- skompiluj ten ciąg do wyrażenia regularnego;
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 flags
jest zdefiniowana w klasie Pattern
i 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 Pattern
jest konstruktorem wyrażeń regularnych. W skrócie metoda compile
wywołuje prywatnego konstruktora klasy Pattern
w 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:
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 |
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 |
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 |
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) |
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:
-
W podanym wzorze pierwszym znakiem jest znak rosyjskiej litery
А
.Matcher
dopasowuje go do każdego znaku tekstu, zaczynając od pozycji zero. Na pozycji zerowej w naszym tekście znajduje się symbolЕ
, czyliMatcher
przechodzi on sekwencyjnie przez znaki w tekście, aż natrafi na dopasowanie do wzorca. W naszym przykładzie jest to symbol na pozycji nr 5. -
Po znalezieniu dopasowania z pierwszym znakiem wzorca
Matcher
sprawdza dopasowanie z drugim znakiem wzorca. W naszym przypadku jest to symbol „.
”, który oznacza dowolny znak.Na szóstej pozycji znajduje się symbol litery
л
. Oczywiście pasuje do wzorca „dowolny znak”. -
Matcher
przechodzi 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,Matcher
pobiera 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).Właściwie
Matcher
chwyta całą linię do końca - tutaj objawia się jego „chciwość”. -
Po
Matcher
dotarciu 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: -
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:
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.
Tryb leniwego kwantyfikatora
-
W tym trybie na początkowym etapie, podobnie jak w trybie zachłannym, szukane jest dopasowanie z pierwszym znakiem wzorca:
-
Następnie szuka dopasowania z kolejnym znakiem we wzorcu – dowolnym znakiem:
-
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,
Matcher
sprawdzi, czy tekst pasuje do reszty wzorca - znaku „а
” . -
Ponieważ nie znaleziono zgodności ze wzorcem w tekście (na pozycji nr 7 w tekście znajduje się symbol „”
л
),Matcher
dodaje 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: -
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.
main
korzystają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
KlasaPattern
posiada 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 flags
wartoś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 limit
określa maksymalną liczbę dopasowań, jakie są wyszukiwane w tekście:
- kiedy – następuje
limit>0
wyszukiwanie 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;
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
Matcher
to 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, Matcher
w 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: StringBuilder
Segment
CharBuffer
Pattern
matcher
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 replaceFirst
tworzą replaceAll
nowy 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 replaceFirst
zastępuje tylko pierwsze dopasowanie i replaceAll
wszystkie 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 Pattern
i Matcher
są wbudowane w String
. Są to metody takie jak split
, matches
, replaceFirst
, replaceAll
. Ale tak naprawdę „pod maską” używają Pattern
i 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 Pattern
i 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 klasyPattern
i używa obiektu klasy Matcher
do 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.
GO TO FULL VERSION