Uprość typowe zadania programistyczne za pomocą interfejsu API Regex
W częściach 1 i 2 tego artykułu zapoznałeś się z wyrażeniami regularnymi i interfejsem API Regex. Poznałeś klasęPattern
i przejrzałeś przykłady demonstrujące konstrukcje wyrażeń regularnych, od prostego dopasowywania wzorców przy użyciu ciągów literałów po bardziej złożone dopasowywanie przy użyciu zakresów, elementów dopasowujących granice i kwantyfikatorów. W tej i kolejnych częściach rozważymy zagadnienia nie omówione w pierwszej części, przestudiujemy odpowiednie metody zajęć Pattern
i Matcher
. PatternSyntaxException
Poznasz także dwa narzędzia, które korzystają z wyrażeń regularnych , aby ułatwić wykonywanie typowych problemów programistycznych. Pierwsza z nich wyodrębnia komentarze z kodu do dokumentacji. Druga to biblioteka kodu wielokrotnego użytku przeznaczona do przeprowadzania analizy leksykalnej - niezbędny element asemblerów, kompilatorów i podobnego oprogramowania.
POBIERZ KOD ŹRÓDŁOWY
Cały kod źródłowy (stworzony przez Jeffa Friesena dla JavaWorld) aplikacji demonstracyjnych opisanych w tym artykule można pobrać stąd .Nauka API Regex
Pattern
i Matcher
są PatternSyntaxException
trzema klasami tworzącymi interfejs API Regex. Każdy z nich udostępnia metody umożliwiające użycie wyrażeń regularnych w kodzie.
Metody klasy Pattern
Instancją klasyPattern
jest skompilowane wyrażenie regularne, zwane także wzorcem. Wyrażenia regularne są kompilowane w celu poprawy wydajności operacji dopasowywania wzorców. Następujące metody statyczne obsługują kompilację.
Pattern compile(String regex)
kompiluje zawartośćregex
w reprezentację pośrednią, która jest przechowywana w nowym plikuPattern
. Ta metoda albo zwraca odwołanie do obiektu, jeśli się powiedzie, albo zgłasza wyjątek,PatternSyntaxException
jeśli wykryta zostanie nieprawidłowa składnia wyrażenia regularnego. Każdy obiekt klasyMatcher
używany przez tenPattern
obiekt lub zwracany przez ten obiekt używa ustawień domyślnych, takich jak wyszukiwanie z rozróżnianiem wielkości liter. Na przykład fragment koduPattern p = Pattern.compile("(?m)^\\.");
tworzy obiektPattern
, który przechowuje skompilowaną reprezentację wyrażenia regularnego w celu dopasowania ciągów znaków rozpoczynających się od znaku kropki.Pattern compile(String regex, int flags)
rozwiązuje ten sam problem coPattern compile(String regex)
, ale biorąc pod uwagęflags
: zestaw stałych bitowych dla flag bitowych typu OR. KlasaPattern
deklaruje stałeCANON_EQ, CASE_INSENSITIVE, COMMENTS, DOTALL, LITERAL, MULTILINE, UNICODE_CASE, UNICODE_CHARACTER_CLASS и UNIX_LINES
, które można łączyć za pomocą bitowego OR (na przykładCASE_INSENSITIVE | DOTALL
) i przekazywać jako argumentflags
.
Z wyjątkiem
CANON_EQ, LITERAL и UNICODE_CHARACTER_CLASS
, te stałe stanowią alternatywę dla zagnieżdżonych wyrażeń flagowych przedstawionych w części 1. Jeśli napotkana zostanie stała flagowa inna niż zdefiniowana w klasie Pattern
, metoda Pattern compile(String regex, int flags)
zgłasza wyjątek java.lang.IllegalArgumentException
. Na przykład Pattern p = Pattern.compile("^\\.", Pattern.MULTILINE);
odpowiednik poprzedniego przykładu, w którym stała Pattern.MULTILINE
i zagnieżdżone wyrażenie flagi (?m)
robią to samo.
Pattern
wraz z używanymi przez nie flagami. Aby to zrobić, możesz wywołać następujące metody:
String pattern()
zwraca oryginalny ciąg wyrażenia regularnego skompilowany do plikuPattern
.int flags()
zwraca flagi obiektuPattern
.
Pattern
zwykle wykorzystuje się go do uzyskania obiektu Matcher
w celu wykonania operacji dopasowywania wzorców. Metoda Matcher matcher(Charsequence input)
tworzy obiekt Matcher
, który wyszukuje w tekście input
dopasowanie do wzorca obiektu Pattern
. Po wywołaniu zwraca referencję do tego obiektu Matcher
. Na przykład polecenie Matcher m = p.matcher(args[1]);
zwraca Matcher
obiekt, Pattern
do którego odwołuje się zmienna p
.
Jednorazowe wyszukiwanie |
---|
Metoda static boolean matches(String regex, CharSequence input) klasowa Pattern pozwala zaoszczędzić na tworzeniu obiektów Pattern i Matcher jednorazowym wyszukiwaniu według szablonu. Ta metoda zwraca wartość true, jeśli input wzorzec jest dopasowany regex , w przeciwnym razie zwraca wartość false. Jeśli wyrażenie regularne zawiera błąd składniowy, metoda zgłasza wyjątek PatternSyntaxException . Na przykład System.out.println(Pattern.matches("[a-z[\\s]]*", "all lowercase letters and whitespace only")); drukuje true , potwierdzając, że fraza all lowercase letters and whitespace only zawiera tylko spacje i małe litery. |
Dzielenie tekstu
Większość programistów przynajmniej raz napisała kod dzielący tekst wejściowy na części składowe, na przykład konwertując tekstowe konto pracownika na zestaw pól. KlasaPattern
zapewnia możliwość wygodniejszego rozwiązania tego żmudnego zadania za pomocą dwóch metod podziału tekstu:
-
Metoda
String[] split(CharSequence text, int limit)
dokonuje podziałutext
według znalezionych dopasowań do wzorca obiektuPattern
i zwraca wyniki w postaci tablicy. Każdy element tablicy określa sekwencję tekstu oddzieloną od następnej sekwencji fragmentem tekstu pasującym do wzorca (lub końcem tekstu). Elementy tablicy są w tej samej kolejności, w jakiej występują wtext
.W tej metodzie liczba elementów tablicy zależy od parametru
limit
, który również kontroluje liczbę znalezionych dopasowań.- Wartość dodatnia powoduje wyszukiwanie nie więcej niż
limit-1
dopasowań, a długość tablicy wynosi nie więcej niżlimit
elementy. - Jeśli wartość jest ujemna, przeszukiwane są wszystkie możliwe dopasowania, a długość tablicy może być dowolna.
- Jeśli wartość wynosi zero, przeszukiwane są wszystkie możliwe dopasowania, długość tablicy może być dowolna, a puste linie na końcu są odrzucane.
- Wartość dodatnia powoduje wyszukiwanie nie więcej niż
- Metoda
String[] split(CharSequence text)
wywołuje poprzednią metodę z 0 jako argumentem ograniczającym i zwraca wynik wywołania.
split(CharSequence text)
rozwiązania problemu podziału konta pracownika na osobne pola imienia i nazwiska, wieku, adresu pocztowego i wynagrodzenia:
Pattern p = Pattern.compile(",\\s");
String[] fields = p.split("John Doe, 47, Hillsboro Road, 32000");
for (int i = 0; i < fields.length; i++)
System.out.println(fields[i]);
Powyższy kod opisuje wyrażenie regularne, które pozwala znaleźć znak przecinka, po którym następuje pojedynczy znak spacji. Oto efekty jego realizacji:
John Doe
47
Hillsboro Road
32000
Predykaty szablonów i interfejs API strumieni
W Javie 8 w klasiePattern
pojawiła się metoda . Ta metoda tworzy predykat (funkcję z wartością logiczną), który służy do dopasowania wzorca. Zastosowanie tej metody pokazano w następującym fragmencie kodu: Predicate
asPredicate()
List progLangs = Arrays.asList("apl", "basic", "c", "c++", "c#", "cobol", "java", "javascript", "perl", "python", "scala");
Pattern p = Pattern.compile("^c");
progLangs.stream().filter(p.asPredicate()).forEach(System.out::println);
Ten kod tworzy listę nazw języków programowania, a następnie kompiluje wzorzec, aby znaleźć wszystkie nazwy zaczynające się na literę c
. Ostatnia linia kodu powyżej implementuje odbieranie szeregowego strumienia danych z tą listą jako źródłem. Konfiguruje filtr za pomocą funkcji logicznej, asPredicate()
która zwraca wartość true, gdy nazwa zaczyna się od litery, c
i wykonuje iterację po strumieniu, wypisując pasujące nazwy na standardowe wyjście. Ta ostatnia linia jest odpowiednikiem następującej regularnej pętli, znanej z aplikacji RegexDemo z Części 1:
for (String progLang: progLangs)
if (p.matcher(progLang).find())
System.out.println(progLang);
Metody klasy Matcher
Instancja klasyMatcher
opisuje mechanizm wykonywania operacji dopasowywania wzorców na sekwencji znaków poprzez interpretację skompilowanego wyrażenia regularnego klasy Pattern
. Obiekty klasy Matcher
obsługują różne rodzaje operacji wyszukiwania wzorców:
-
Metoda
boolean find()
przeszukuje tekst wejściowy pod kątem następnego dopasowania. Ta metoda rozpoczyna skanowanie od początku określonego tekstu lub od pierwszego znaku po poprzednim dopasowaniu. Druga opcja jest możliwa tylko wtedy, gdy poprzednie wywołanie tej metody zwróciło wartość true, a mechanizm rozpoznawania nazw nie został zresetowany. W każdym przypadku, jeśli wyszukiwanie zakończy się pomyślnie, zwracana jest wartość logiczna true. Przykład tej metody można znaleźć wRegexDemo
Części 1. -
Metoda
boolean find(int start)
resetuje moduł dopasowujący i przeszukuje tekst w poszukiwaniu następnego dopasowania. Przeglądanie rozpoczyna się od pozycji określonej parametremstart
. Jeśli wyszukiwanie zakończy się pomyślnie, zwracana jest wartość logiczna true. Na przykładm.find(1);
skanuje tekst zaczynając od pozycji1
(pozycja 0 jest ignorowana). Jeśli parametrstart
zawiera wartość ujemną lub wartość większą niż długość tekstu elementu dopasowującego, metoda zgłasza wyjątekjava.lang.IndexOutOfBoundsException
. -
Metoda
boolean matches()
próbuje dopasować cały tekst do wzorca. Zwraca wartość logiczną true, jeśli cały tekst pasuje do wzorca. Na przykład kodPattern p = Pattern.compile("\\w*"); Matcher m = p.matcher("abc!"); System.out.println(p.matches());
generuje wynik ,false
ponieważ znak!
nie jest znakiem słownym. -
Metoda
boolean lookingAt()
próbuje dopasować podany tekst do wzorca. Ta metoda zwraca wartość true, jeśli jakakolwiek część tekstu pasuje do wzorca. W przeciwieństwie do metodymatches();
, nie cały tekst musi pasować do wzorca. Na przykładPattern p = Pattern.compile("\\w*"); Matcher m = p.matcher("abc!"); System.out.println(p.lookingAt());
wyświetlitrue
, ponieważ początek tekstuabc!
składa się tylko ze znaków słowotwórczych.
Pattern
, obiekty klas Matcher
zachowują informacje o stanie. Czasami może być konieczne zresetowanie modułu dopasowującego, aby wyczyścić te informacje po zakończeniu wyszukiwania wzorców. Dostępne są następujące metody resetowania modułu rozpoznawania nazw:
-
Metoda
Matcher reset()
resetuje stan mechanizmu dopasowującego, łącznie z pozycją, która ma zostać dołączona na końcu (resetowana do 0). Następna operacja wyszukiwania wzorca rozpoczyna się na początku tekstu dopasowującego. Zwraca referencję do bieżącego obiektuMatcher
. Na przykładm.reset();
resetuje program rozpoznawania nazw, do którego odwołuje sięm
. -
Metoda
Matcher reset(CharSequence text)
resetuje stan mechanizmu rozpoznawania nazw i ustawia nowy tekst mechanizmu rozpoznawania nazw natext
. Następna operacja wyszukiwania wzorca rozpoczyna się na początku nowego tekstu dopasowującego. Zwraca referencję do bieżącego obiektuMatcher
. Na przykładm.reset("new text");
resetuje przywoływany program rozpoznawania nazwm
i ustawia nowy tekst mechanizmu rozpoznawania nazw na"new text"
.
Dodanie tekstu na końcu
Pozycja elementu dopasowującego, który ma zostać dodany na końcu, określa początek tekstu dopasowującego, który jest dodawany na końcu obiektu typujava.lang.StringBuffer
. Następujące metody wykorzystują tę pozycję:
-
Metoda
Matcher appendReplacement(StringBuffer sb, String replacement)
odczytuje znaki tekstu dopasowującego i dołącza je na końcu obiektu, do któregoStringBuffer
odwołuje się argumentsb
. Ta metoda zatrzymuje czytanie na ostatnim znaku poprzedzającym poprzednie dopasowanie wzorca. Następnie metoda dołącza znaki z obiektu typu, doString
którego odwołuje się argument,replacement
na koniec obiektuStringBuffer
(łańcuch może zawierać odniesienia do ciągów tekstowych przechwyconych podczas poprzedniego wyszukiwania; są one określane na podstawie przechwytywanychreplacement
znaków i numerów grup).($)
Na koniec metoda ustawia wartość pozycji elementu dopasowującego, która ma zostać dołączona do pozycji ostatniego dopasowanego znaku plus jeden, a następnie zwraca odwołanie do bieżącego elementu dopasowującego. -
Metoda
StringBuffer appendTail(StringBuffer sb)
dodaje cały tekst do obiektuStringBuffer
i zwraca odwołanie do tego obiektu. Po ostatnim wywołaniu metodyappendReplacement(StringBuffer sb, String replacement)
wywołaj metodę,appendTail(StringBuffer sb)
aby skopiować pozostały tekst do obiektuStringBuffer
.
Metoda Matcher appendReplacement(StringBuffer sb, String replacement)
zgłasza wyjątek java.lang.IllegalStateException
, jeśli moduł dopasowujący nie znalazł jeszcze dopasowania lub poprzednia próba wyszukiwania nie powiodła się. Zgłasza wyjątek, IndexOutOfBoundsException
jeśli linia replacement
określa grupę przechwytywania, której nie ma we wzorcu).
Przechwycone grupy |
---|
Jak pamiętasz z części 1, grupa przechwytywania to sekwencja znaków ujęta w nawiasy ( () ) metaznaki. Celem tej konstrukcji jest przechowywanie znalezionych znaków do późniejszego ponownego wykorzystania podczas dopasowywania wzorców. Podczas wyszukiwania wzorców wszystkie znaki z przechwyconej grupy są traktowane jako jedna całość. |
appendReplacement(StringBuffer sb, String replacement)
i appendTail(StringBuffer sb
w celu zamiany wszystkich wystąpień sekwencji znaków w tekście źródłowym cat
na caterpillar
:
Pattern p = Pattern.compile("(cat)");
Matcher m = p.matcher("one cat, two cats, or three cats on a fence");
StringBuffer sb = new StringBuffer();
while (m.find())
m.appendReplacement(sb, "$1erpillar");
m.appendTail(sb);
System.out.println(sb);
Użycie przechwyconej grupy i odniesienia do niej w tekście zastępczym nakazuje programowi wstawienie erpillar
po każdym wystąpieniu cat
. Wynik wykonania tego kodu wygląda następująco: one caterpillar, two caterpillars, or three caterpillars on a fence
Zastępowanie tekstu
KlasaMatcher
udostępnia nam dwie metody zastępowania tekstu, uzupełniające metodę appendReplacement(StringBuffer sb, String replacement)
. Korzystając z tych metod, możesz zastąpić pierwsze wystąpienie [zastąpionego tekstu] lub wszystkie wystąpienia:
-
Metoda
String replaceFirst(String replacement)
resetuje mechanizm dopasowujący, tworzy nowy obiektString
, kopiuje wszystkie znaki tekstu dopasowującego (aż do pierwszego dopasowania) do tego ciągu, dołącza znaki od jego końcareplacement
, kopiuje pozostałe znaki do ciągu i zwraca obiektString
(ciągreplacement
może zawierać odniesienia do tych przechwyconych podczas poprzednich sekwencji tekstu wyszukiwania przy użyciu symboli dolara i przechwyconych numerów grup). -
Metoda
String replaceAll(String replacement)
działa podobnie jak metodaString replaceFirst(String replacement)
, z tą różnicą, że wszystkie znalezione dopasowania zastępujereplacement
znakami z ciągu znaków.
\s+
wyszukuje jeden lub więcej białych znaków w tekście wejściowym. Poniżej użyjemy tego wyrażenia regularnego i wywołamy metodę replaceAll(String replacement)
usuwania zduplikowanych spacji:
Pattern p = Pattern.compile("\\s+");
Matcher m = p.matcher("Удаляем \t\t лишние пробелы. ");
System.out.println(m.replaceAll(" "));
Oto wyniki: Удаляем лишние пробелы.
Wyrażenia regularne w Javie, część 4 Wyrażenia regularne w Javie, część 5
GO TO FULL VERSION