JavaRush /Blog Java /Random-PL /Wyrażenia regularne w Javie, część 2

Wyrażenia regularne w Javie, część 2

Opublikowano w grupie Random-PL
Przedstawiamy Państwu tłumaczenie krótkiego przewodnika po wyrażeniach regularnych w Javie, napisanego przez Jeffa Friesena dla serwisu javaworld . Dla ułatwienia czytania artykuł podzieliliśmy na kilka części. Wyrażenia regularne w Javie, część 2 - 1Wyrażenia regularne w Javie, część 1
Łączenie wielu zakresów
Możesz połączyć wiele zakresów w jedną klasę znaków, umieszczając je obok siebie. Na przykład klasa [a-zA-Z]dopasowuje wszystkie znaki alfabetu łacińskiego pisane małymi lub dużymi literami.

Łączenie wielu zakresów

Możesz połączyć wiele zakresów w jedną klasę znaków, umieszczając je obok siebie. Na przykład klasa [a-zA-Z]dopasowuje wszystkie znaki alfabetu łacińskiego pisane małymi lub dużymi literami.

Łączenie klas postaci

Unia klas znaków składa się z kilku zagnieżdżonych klas znaków i dopasowuje wszystkie znaki w powstałej unii. Na przykład klasa [a-d[m-p]]dopasowuje znaki od ado di od mdo p. Rozważmy następujący przykład: Ten java RegexDemo [ab[c-e]] abcdef przykład znajdzie znaki a, b, i , dla których istnieją dopasowania w : cdeabcdef
regex = [ab[c-e]]
input = abcdef
Found [a] starting at 0 and ending at 0
Found [b] starting at 1 and ending at 1
Found [c] starting at 2 and ending at 2
Found [d] starting at 3 and ending at 3
Found [e] starting at 4 and ending at 4

Przecięcie klas znaków

Przecięcie klas znaków składa się ze znaków wspólnych dla wszystkich klas zagnieżdżonych i pasuje tylko do znaków wspólnych. Na przykład klasa [a-z&&[d-f]]dopasowuje znaki di e. fRozważmy następujący przykład: java RegexDemo "[aeiouy&&[y]]" party Należy pamiętać, że w moim systemie operacyjnym Windows wymagane są podwójne cudzysłowy, ponieważ powłoka poleceń traktuje je &jako separator poleceń. W tym przykładzie zostanie znaleziony tylko znak y, który ma dopasowanie w party:
regex = [aeiouy&&[y]]
input = party
Found [y] starting at 4 and ending at 4

Odejmowanie klas znaków

Odejmowanie klas znaków obejmuje wszystkie znaki z wyjątkiem tych zawartych w zagnieżdżonych klasach znaków i dopasowuje tylko pozostałe znaki. Na przykład klasa [a-z&&[^m-p]]dopasowuje znaki od ado li od qdo z: java RegexDemo "[a-f&&[^a-c]&&[^e]]" abcdefg W tym przykładzie zostaną znalezione znaki di fdla których istnieją dopasowania w abcdefg:
regex = [a-f&&[^a-c]&&[^e]]
input = abcdefg
Found [d] starting at 3 and ending at 3
Found [f] starting at 5 and ending at 5

Predefiniowane klasy znaków

Niektóre klasy znaków pojawiają się w wyrażeniach regularnych na tyle często , że uzasadnia to użycie notacji skróconej. Klasa Patternoferuje predefiniowane klasy znaków jako takie skróty. Można ich używać do upraszczania wyrażeń regularnych i minimalizowania błędów składniowych. Istnieje kilka kategorii predefiniowanych klas znaków: java.lang.Characterwłaściwości standardowe, POSIX i Unicode, takie jak skrypt, blok, kategoria i plik binarny. Poniższa lista przedstawia jedynie kategorię klas standardowych:
  • \d: Numer. Równoważne [0-9].
  • \D: Znak nienumeryczny. Równoważne [^0-9].
  • \s: Znak odstępu. Równoważne [ \t\n\x0B\f\r].
  • \S: Nie jest to znak odstępu. Równoważne [^\s].
  • \w: Symbol słowotwórczy. Równoważne [a-zA-Z_0-9].
  • \W: Nie jest postacią słowotwórczą. Równoważne [^\w].
W poniższym przykładzie użyto predefiniowanej klasy znaków \wdo opisania wszystkich znaków wyrazów w tekście wejściowym: java RegexDemo \w "aZ.8 _" Przyjrzyj się uważnie następującym wynikom wykonania, które pokazują, że kropki i spacje nie są uznawane za znaki słowne:
regex = \w
input = aZ.8 _
Found [a] starting at 0 and ending at 0
Found [Z] starting at 1 and ending at 1
Found [8] starting at 3 and ending at 3
Found [_] starting at 5 and ending at 5
Separatory linii
Dokumentacja zestawu SDK klasy Patternopisuje metaznak kropki jako predefiniowaną klasę znaków, która pasuje do dowolnego znaku z wyjątkiem separatorów linii (sekwencje jedno- lub dwuznakowe oznaczające koniec linii). Wyjątkiem jest tryb kropkowy (który omówimy dalej), w którym kropki dopasowują się również do separatorów linii. Klasa Patternrozróżnia następujące separatory linii:
  • znak powrotu karetki ( \r);
  • znak nowej linii (symbol przesunięcia papieru o jedną linię) ( \n);
  • znak powrotu karetki, po którym następuje znak nowej linii ( \r\n);
  • znak następnego wiersza ( \u0085);
  • znak separatora linii ( \u2028);
  • symbol separatora akapitu ( \u2029)

Przechwycone grupy

Grupa przechwytująca służy do zapisywania znalezionego zestawu znaków do dalszego wykorzystania podczas wyszukiwania według wzorca. Konstrukcja ta jest ciągiem znaków ujętych w metaznaki w nawiasach ( ( )). Podczas wyszukiwania według wzorca wszystkie znaki w przechwyconej grupie są traktowane jako jedna całość. Na przykład grupa przechwytywania ( Java) łączy litery J, ai w jedną jednostkę. Ta grupa przechwytywania wyszukuje wszystkie wystąpienia wzorca w tekście wejściowym. Przy każdym dopasowaniu poprzednie zapisane znaki są zastępowane przez kolejne. Przechwycone grupy można zagnieżdżać w innych przechwyconych grupach. Na przykład w wyrażeniu regularnym grupa jest zagnieżdżona w grupie . Każdej zagnieżdżonej lub niezagnieżdżonej grupie przechwytywania przypisany jest numer, zaczynając od 1, a numeracja przebiega od lewej do prawej. W poprzednim przykładzie dopasowuje grupę przechwytywania numer 1 i grupę przechwytywania numer 2. W wyrażeniu regularnym dopasowuje grupę przechwytywania numer 1 i grupę przechwytywania numer 2. Dostęp do dopasowań przechowywanych przez grupy przechwytywania można później uzyskać za pomocą odwołań wstecznych. Określone jako ukośnik odwrotny, po którym następuje znak numeryczny odpowiadający numerowi przechwytywanej grupy, odwołanie wsteczne umożliwia odwoływanie się do znaków w tekście przechwyconym przez grupę. Posiadanie linku zwrotnego powoduje, że moduł dopasowujący odwołuje się do zapisanego wyniku wyszukiwania przechwyconej grupy w oparciu o znajdujący się w nim numer, a następnie używa znaków z tego wyniku do podjęcia próby dalszego wyszukiwania. Poniższy przykład ilustruje użycie odwołania wstecznego do znalezienia błędów gramatycznych w tekście: W tym przykładzie użyto wyrażenia regularnego do znalezienia błędu gramatycznego ze zduplikowanym słowem bezpośrednio po tekście wejściowym . To wyrażenie regularne określa dwie grupy do przechwycenia: numer 1 – , odpowiadający i numer 2 – , odpowiadający znakowi spacji, po którym następuje . Odwołanie wsteczne umożliwia ponowne przejrzenie zapisanego wyniku grupy nr 2, dzięki czemu funkcja dopasowująca może wyszukać drugie wystąpienie spacji, po której następuje , natychmiast po pierwszym wystąpieniu spacji i . Wyniki pojedynku przedstawiają się następująco: vaJavaJava(Java( language))(language)(Java)(Java( language))(language)(a)(b)(a)(b)Wyrażenia regularne w Javie, część 2 - 2java RegexDemo "(Java( language)\2)" "The Java language language"(Java( language)\2)languageJava"The Java language language"(Java( language)\2)Java language language(language)language\2languagelanguageRegexDemo
regex = (Java( language)\2)
input = The Java language language
Found [Java language language] starting at 4 and ending at 25

Dopasowujące granice

Czasami trzeba wykonać dopasowanie wzorca na początku linii, na granicach wyrazów, na końcu tekstu itp. Można to zrobić, korzystając z jednego z elementów dopasowujących krawędzi klasy Pattern, które są konstrukcjami wyrażeń regularnych wyszukujących dopasowania w następujących lokalizacjach:
  • ^: Początek linii;
  • $: Koniec linii;
  • \b: Granica słowa;
  • \B: Granica pseudosłowa;
  • \A: Początek tekstu;
  • \G: Koniec poprzedniego meczu;
  • \Z: Koniec tekstu, z wyłączeniem separatora linii końcowej (jeśli występuje);
  • \z: Koniec tekstu
W poniższym przykładzie zastosowano ^metaznak dopasowujący granicę do wyszukiwania linii rozpoczynających się od The, po których następuje zero lub więcej znaków słowa: java RegexDemo "^The\w*" Therefore Znak ^określa, że ​​pierwsze trzy znaki tekstu wejściowego muszą odpowiadać kolejnym znakom wzorca T, hi e, po których może następować dowolna liczba symboli słowotwórczych. Oto wynik wykonania:
regex = ^The\w*
input = Therefore
Found [Therefore] starting at 0 and ending at 8
Co się stanie, jeśli zmienisz wiersz poleceń na java RegexDemo "^The\w*" " Therefore"? Nie zostanie znalezione żadne dopasowanie, ponieważ Thereforetekst wejściowy jest poprzedzony znakiem spacji.

Dopasowania o zerowej długości

Czasami podczas pracy z urządzeniami dopasowującymi krawędzie można spotkać dopasowania o zerowej długości. Совпадение нулевой длиныto dopasowanie, które nie zawiera żadnych znaków. Mogą one występować w pustym tekście wejściowym, na początku tekstu wejściowego, po ostatnim znaku tekstu wejściowego oraz pomiędzy dowolnymi dwoma znakami tekstu wejściowego. Dopasowania o zerowej długości są łatwe do rozpoznania, ponieważ zawsze zaczynają się i kończą w tej samej pozycji. Rozważmy następujący przykład: java RegExDemo \b\b "Java is" Ten przykład wyszukuje dwie kolejne granice słów, a wyniki wyglądają następująco:
regex = \b\b
input = Java is
Found [] starting at 0 and ending at -1
Found [] starting at 4 and ending at 3
Found [] starting at 5 and ending at 4
Found [] starting at 7 and ending at 6
W wynikach widzimy kilka dopasowań o zerowej długości. Pozycje końcowe są tutaj o jeden mniejsze niż pozycje początkowe, ponieważ RegexDemookreśliłem je w kodzie źródłowym na Listingu 1 end() – 1. Wyrażenia regularne w Javie, część 2–3

Kwantyfikatory

Kwantyfikator to konstrukcja wyrażenia regularnego, która jawnie lub pośrednio wiąże wzorzec z wartością liczbową. Ta wartość liczbowa określa, ile razy należy szukać wzorca. Kwantyfikatory dzielą się na zachłanne, leniwe i superchciwe:
  • Kwantyfikator zachłanny ( ?, *lub +) ma na celu znalezienie najdłuższego dopasowania. Czy mogę zapytać X? znaleźć jedno lub mniej wystąpień X, X*znaleźć zero lub więcej wystąpień X, X+znaleźć jedno lub więcej wystąpień X, X{n}znaleźć nwystąpienia X, X{n,}znaleźć co najmniej (i prawdopodobnie więcej) nwystąpień Xoraz X{n,m}znaleźć co najmniej , nale nie więcej mwystąpień X.
  • Leniwy kwantyfikator ( ??, *?lub +?) ma na celu znalezienie najkrótszego dopasowania. Można określić X??wyszukiwanie jednego lub mniejszej liczby wystąpień X, X*? znaleźć zero lub więcej wystąpień X, X+?znaleźć jedno lub więcej wystąpień X, X{n}?znaleźć nwystąpienia X, X{n,}?znaleźć co najmniej (i prawdopodobnie więcej) nwystąpień Xoraz X{n,m}?znaleźć co najmniej , nale nie więcej niż mwystąpienia X.
  • Kwantyfikator super zachłanny ( ?+, *+lub ++) jest podobny do kwantyfikatora zachłannego, z tą różnicą, że kwantyfikator super zachłanny podejmuje tylko jedną próbę znalezienia najdłuższego dopasowania, podczas gdy kwantyfikator zachłanny może podejmować wiele prób. Można ustawić X?+, aby znaleźć jedno lub mniej wystąpień X, X*+znaleźć zero lub więcej wystąpień X, X++znaleźć jedno lub więcej wystąpień X, X{n}+znaleźć nwystąpienia X, X{n,}+znaleźć co najmniej (i prawdopodobnie więcej) nwystąpień Xoraz X{n,m}+ znaleźć co najmniej , nale nie więcej niż mwystąpienia X.
Poniższy przykład ilustruje użycie zachłannego kwantyfikatora: java RegexDemo .*ox "fox box pox" Oto wyniki:
regex = .*ox
input = fox box pox
Found [fox box pox] starting at 0 and ending at 10
Kwantyfikator zachłanny ( .*) znajduje najdłuższą sekwencję znaków kończącą się na ox. Zużywa cały tekst wejściowy, a następnie wycofuje się do momentu wykrycia, że ​​tekst wejściowy kończy się tymi znakami. Rozważmy teraz leniwy kwantyfikator: java RegexDemo .*?ox "fox box pox" jego wyniki:
regex = .*?ox
input = fox box pox
Found [fox] starting at 0 and ending at 2
Found [ box] starting at 3 and ending at 6
Found [ pox] starting at 7 and ending at 10
Leniwy kwantyfikator ( .*?) znajduje najkrótszą sekwencję znaków kończącą się na ox. Zaczyna się od pustego ciągu i stopniowo zużywa znaki, aż znajdzie dopasowanie. A następnie kontynuuje pracę, aż do wyczerpania tekstu wejściowego. Na koniec spójrzmy na super-chciwy kwantyfikator: java RegexDemo .*+ox "fox box pox" A oto jego wyniki:
regex = .*+ox
input = fox box pox
Bardzo zachłanny kwantyfikator ( .*+) nie znajduje dopasowań, ponieważ zużywa cały tekst wejściowy i oxna końcu wyrażenia regularnego nie ma już nic do dopasowania. W przeciwieństwie do kwantyfikatora zachłannego, kwantyfikator superchciwy nie cofa się.

Dopasowania o zerowej długości

Czasami podczas pracy z kwantyfikatorami napotkasz dopasowania o zerowej długości. Na przykład użycie następującego kwantyfikatora zachłannego skutkuje wieloma dopasowaniami o zerowej długości: java RegexDemo a? abaa Wyniki uruchomienia tego przykładu:
regex = a?
input = abaa
Found [a] starting at 0 and ending at 0
Found [] starting at 1 and ending at 0
Found [a] starting at 2 and ending at 2
Found [a] starting at 3 and ending at 3
Found [] starting at 4 and ending at 3
W wynikach wykonania znajduje się pięć dopasowań. Choć pierwsza, trzecia i czwarta są dość oczekiwane (odpowiadają pozycjom trzech liter aw abaa), druga i piąta mogą Cię zaskoczyć. Wydaje się, że wskazują, co aodpowiada bkońcowi tekstu, ale w rzeczywistości tak nie jest. Wyrażenie regularne a?nie wyszukuje bna końcu tekstu. Szuka obecności lub nieobecności a. Jeśli a?nie znajdzie a, zgłasza to jako dopasowanie o zerowej długości.

Zagnieżdżone wyrażenia flagowe

Dopasowujące przyjmują pewne domyślne założenia, które można zastąpić podczas kompilowania wyrażenia regularnego we wzorzec. Omówimy tę kwestię później. Wyrażenie regularne pozwala zastąpić dowolne wartości domyślne za pomocą zagnieżdżonego wyrażenia flagowego. Ta konstrukcja wyrażenia regularnego jest określona jako metaznak złożony z nawiasów wokół metaznaku znaku zapytania ( ?), po którym następuje mała litera łacińska. Klasa Patternrozumie następujące zagnieżdżone wyrażenia flagowe:
  • (?i): Włącza dopasowywanie wzorców bez uwzględniania wielkości liter. Na przykład podczas korzystania z polecenia java RegexDemo (?i)tree Treehousesekwencja znaków Treeodpowiada wzorowi tree. Wartość domyślna to wyszukiwanie wzorców z uwzględnieniem wielkości liter.
  • (?x): Zezwala na użycie białych znaków i komentarzy zaczynających się od metaznaku we wzorcu #. Dopasowujący zignoruje oba. Przykładowo dla java RegexDemo ".at(?x)#match hat, cat, and so on" matterciągu znaków matodpowiada wzorowi .at. Domyślnie białe znaki i komentarze są niedozwolone, a moduł dopasowujący traktuje je jako znaki biorące udział w wyszukiwaniu.
  • (?s): Włącza tryb kropkowy, w którym metaznak kropki dopasowuje separatory linii oprócz wszelkich innych znaków. Na przykład polecenie java RegexDemo (?s). \nznajdzie znak nowej linii. Wartość domyślna jest przeciwieństwem dotall: nie zostaną znalezione żadne separatory linii. Na przykład polecenie Java RegexDemo . \nnie znajdzie znaku nowej linii.
  • (?m): Włącza tryb wielowierszowy, w którym ^dopasowuje początek i $koniec każdej linii. Na przykład java RegexDemo "(?m)^abc$" abc\nabcznajduje obie sekwencje w tekście wejściowym abc. Domyślnie używany jest tryb jednowierszowy: ^dopasowuje początek całego wprowadzonego tekstu i $dopasowuje jego koniec. Na przykład java RegexDemo "^abc$" abc\nabczwraca odpowiedź, że nie ma żadnych dopasowań.
  • (?u): Włącza wyrównanie wielkości liter z uwzględnieniem Unicode. Ta flaga, używana w połączeniu z (?i), umożliwia dopasowywanie wzorców bez uwzględniania wielkości liter, zgodnie ze standardem Unicode. Domyślnym ustawieniem jest wyszukiwanie wyłącznie znaków z uwzględnieniem wielkości liter i znaków US-ASCII.
  • (?d): Włącza tryb ciągów w stylu uniksowym, w którym funkcja dopasowująca rozpoznaje metaznaki w kontekście .i tylko separator linii . Domyślnym trybem jest tryb ciągów w stylu innym niż Unix: moduł dopasowujący rozpoznaje, w kontekście powyższych metaznaków, wszystkie ograniczniki linii.^$\n
Zagnieżdżone wyrażenia flagowe przypominają przechwycone grupy, ponieważ ich znaki są otoczone metaznakami w nawiasach. W przeciwieństwie do grup przechwyconych, wyrażenia flag zagnieżdżonych są przykładem grup nieprzechwyconych, które są konstrukcją wyrażenia regularnego, która nie przechwytuje znaków tekstowych. Definiuje się je jako ciągi znaków otoczone metaznakami w nawiasach.
Określanie wielu zagnieżdżonych wyrażeń flag
Możliwe jest określenie wielu zagnieżdżonych wyrażeń flag w wyrażeniu regularnym, umieszczając je obok siebie ( (?m)(?i))) lub umieszczając litery je definiujące sekwencyjnie ( (?mi)).

Wniosek

Jak już zapewne zauważyłeś, wyrażenia regularne są niezwykle przydatne, a stają się jeszcze bardziej przydatne, gdy opanujesz niuanse ich składni. Jak dotąd zapoznałem Cię z podstawami wyrażeń regularnych i Pattern. W części 2 przyjrzymy się bliżej API Regex i poznamy metody metod Pattern, Matcheri PatternSyntaxException. Pokażę Ci także dwa praktyczne zastosowania Regex API, które możesz od razu zastosować w swoich programach. Wyrażenia regularne w Javie, część 3 Wyrażenia regularne w Javie, część 4 Wyrażenia regularne w Javie, część 5
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION