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

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

Opublikowano w grupie Random-PL
Zwracamy uwagę na tłumaczenie krótkiego przewodnika po wyrażeniach regularnych w języku Java, napisanego przez Jeffa Friesena dla serwisu JavaWorld . Dla ułatwienia czytania artykuł podzieliliśmy na kilka części. Wyrażenia regularne w Javie, część 1 - 1

Wykorzystanie API wyrażeń regularnych w programach Java do rozpoznawania i opisywania wzorców

Znaki Java i różne typy danych łańcuchowych zapewniają niskopoziomową obsługę dopasowywania wzorców, ale używanie ich w tym celu zazwyczaj powoduje znaczną złożoność kodu. Prostszy i bardziej wydajny kod uzyskuje się dzięki zastosowaniu Regex API („API wyrażeń regularnych”). Ten samouczek pomoże Ci rozpocząć pracę z wyrażeniami regularnymi i interfejsem API Regex. Najpierw omówimy ogólnie trzy najciekawsze klasy w pakiecie java.util.regex, a następnie zajrzymy do wnętrza klasy Patterni przeanalizujemy jej wyrafinowane konstrukcje dopasowujące wzorce. Uwaga: Możesz pobrać kod źródłowy (utworzony przez Jeffa Friesena dla witryny JavaWorld) aplikacji demonstracyjnej z tego artykułu tutaj .

Co to są wyrażenia regularne?

Wyrażenie regularne (wyrażenie regularne/regex/regexp) to ciąg znaków będący wzorcem opisującym pewien zestaw ciągów. Wzorzec określa, które wiersze należą do zestawu. Wzorzec składa się z literałów i metaznaków — znaków o specjalnym znaczeniu, a nie dosłownym. Dopasowywanie wzorców to wyszukiwanie tekstu w celu znalezienia dopasowań, czyli ciągów znaków pasujących do wzorca wyrażenia regularnego. Java obsługuje dopasowywanie wzorców za pośrednictwem interfejsu API Regex. To API składa się z trzech klas: Pattern, Matcheri PatternSyntaxException, znajdujących się w pakiecie java.util.regex:
  • obiekty klas Pattern, zwane także szablonami, są kompilowanymi wyrażeniami regularnymi.
  • obiekty klas Matcher, czyli elementy dopasowujące, to mechanizmy interpretacji wzorców służące do wyszukiwania dopasowań w sekwencjach znaków (obiekty, których klasy implementują interfejs java.lang.CharSequencei służą jako źródła tekstu).
  • Obiekty klas PatternSyntaxExceptionsłużą do opisywania nieprawidłowych wzorców wyrażeń regularnych.
Java zapewnia także obsługę dopasowywania wzorców za pomocą różnych metod platformy java.lang.String. Na przykład funkcja boolean matches (String regex)zwraca truetylko wtedy, gdy ciąg wywołujący dokładnie pasuje do wyrażenia regularnego regex.
Wygodne metody
matches()oraz inne wygodne metody tej klasy, zorientowane na wyrażenia regularne, Stringsą implementowane pod maską w sposób podobny do API Regex.

RegexDemo

Stworzyłem aplikację RegexDemo, która demonstruje wyrażenia regularne Java i różne metody Pattern, Matcheri PatternSyntaxException. Poniżej znajduje się kod źródłowy tej aplikacji demonstracyjnej. Listing 1. Demonstracja wyrażeń regularnych
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
public class RegexDemo
{
   public static void main(String[] args)
   {
      if (args.length != 2)
      {
         System.err.println("usage: java RegexDemo regex input");
         return;
      }
      // Преобразуем символьные последовательности начала новой строки (\n) в символы начала строки.
      args[1] = args[1].replaceAll("\\\\n", "\n");
      try
      {
         System.out.println("regex = " + args[0]);
         System.out.println("input = " + args[1]);
         Pattern p = Pattern.compile(args[0]);
         Matcher m = p.matcher(args[1]);
         while (m.find())
            System.out.println("Found [" + m.group() + "] starting at "
                               + m.start() + " and ending at " + (m.end() - 1));
      }
      catch (PatternSyntaxException pse)
      {
         System.err.println("Неправильное регулярное выражение: " + pse.getMessage());
         System.err.println("Описание: " + pse.getDescription());
         System.err.println("Позиция: " + pse.getIndex());
         System.err.println("Неправильный шаблон: " + pse.getPattern());
      }
   }
}
Pierwszą rzeczą , jaką robi metoda mainklasowa RegexDemo, jest sprawdzenie wiersza poleceń. Wymaga dwóch argumentów: pierwszy jest wyrażeniem regularnym, a drugi jest tekstem wejściowym, w którym wyrażenie regularne będzie przeszukiwane. Może zaistnieć potrzeba użycia znaku nowego wiersza w tekście wejściowym (\n). Można to zrobić jedynie poprzez określenie znaku, \po którym następuje znak n. Funkcja main()konwertuje tę sekwencję znaków na wartość Unicode 10. Wyrażenia regularne w Javie, część 1–2Większość kodu RegexDemojest ujęta w rozszerzenie try-catch. Blok trynajpierw wyprowadza dane wyrażenie regularne i tekst wejściowy, a następnie tworzy obiekt Patternprzechowujący skompilowane wyrażenie regularne (wyrażenia regularne są kompilowane w celu poprawy wydajności dopasowywania wzorców). Funkcja dopasowująca jest wyodrębniana z obiektu Patterni używana do iteracyjnego wyszukiwania dopasowań, aż do znalezienia wszystkich. Blok catchwywołuje kilka metod klas PatternSyntaxExceptionw celu pobrania przydatnych informacji o wyjątku. Informacje te są kolejno przesyłane do strumienia wyjściowego. Nie trzeba jeszcze znać szczegółów działania kodu: staną się one jasne, gdy przestudiujemy API w drugiej części artykułu. Jednakże musisz skompilować Listing 1. Weź kod z Listingu 1, a następnie wpisz następujące polecenie w wierszu poleceń, aby skompilować RegexDemo: javac RegexDemo.java

Klasa Pattern i jej konstrukcje

Klasa Pattern, pierwsza z trzech klas tworzących interfejs API Regex, jest skompilowaną reprezentacją wyrażenia regularnego. Dokumentacja zestawu SDK klasy Patternopisuje różne konstrukcje wyrażeń regularnych, ale jeśli nie używasz aktywnie wyrażeń regularnych, części tej dokumentacji mogą być mylące. Czym są kwantyfikatory i jaka jest różnica między kwantyfikatorami zachłannymi, niechętnymi i zaborczymi? Co to są klasy znaków, elementy dopasowujące granice, odniesienia wsteczne i wyrażenia z osadzoną flagą? Na te i inne pytania odpowiem w kolejnych rozdziałach.

Dosłowne ciągi znaków

Najprostszą konstrukcją wyrażenia regularnego jest ciąg literału. Aby dopasowanie wzorca powiodło się, pewna część tekstu wejściowego musi pasować do wzorca tej konstrukcji. Rozważmy następujący przykład: java RegexDemo apple applet W tym przykładzie próbujemy znaleźć dopasowanie do wzorca applew tekście wejściowym applet. Poniższy wynik pokazuje znalezione dopasowanie:
regex = apple
input = applet
Found [apple] starting at 0 and ending at 4
Na wyjściu widzimy wyrażenie regularne i tekst wejściowy, a następnie informację o pomyślnym wykryciu appleapletu. Dodatkowo podane są pozycje początkowe i końcowe tego meczu: 0i 4, odpowiednio. Pozycja początkowa wskazuje pierwsze miejsce w tekście, w którym znaleziono dopasowanie, a pozycja końcowa wskazuje ostatni punkt dopasowania. Załóżmy teraz, że wydaliśmy następującą linię poleceń: java RegexDemo apple crabapple Tym razem otrzymujemy następujący wynik, z różnymi pozycjami początkowymi i końcowymi:
regex = apple
input = crabapple
Found [apple] starting at 4 and ending at 8
W przeciwnym razie, z i appletjako wyrażenie regularne apple- tekst wejściowy, nie zostaną znalezione żadne dopasowania. Całe wyrażenie regularne musi pasować, ale w tym przypadku tekst wejściowy nie zawiera tpo apple. Wyrażenia regularne w Javie, część 1–3

Metaznaki

Bardziej interesujące konstrukcje wyrażeń regularnych łączą znaki dosłowne z metaznakami. Na przykład w wyrażeniu regularnym a.bmetaznak kropki (.)oznacza dowolny znak pomiędzy ai b. Rozważmy następujący przykład: java RegexDemo .ox "The quick brown fox jumps over the lazy ox." W tym przykładzie użyto .oxzarówno wyrażenia regularnego, jak i The quick brown fox jumps over the lazy ox.tekstu wejściowego. RegexDemoprzeszukuje tekst pod kątem dopasowań zaczynających się od dowolnego znaku i kończących się na. ox.Wyniki jego wykonania są następujące:
regex = .ox
input = The quick brown fox jumps over the lazy ox.
Found [fox] starting at 16 and ending at 18
Found [ ox] starting at 39 and ending at 41
Na wyjściu widzimy dwa dopasowania: foxi ox(ze znakiem spacji przed nim). Metaznak . dopasowuje znak fw pierwszym przypadku i spację w drugim. Co się stanie, jeśli zastąpisz go .oxmetaznakiem .? Oznacza to, co otrzymamy w wyniku następującego wiersza poleceń: java RegexDemo . "The quick brown fox jumps over the lazy ox." Ponieważ metaznak kropki pasuje do dowolnego znaku, RegexDemowyświetli znalezione dopasowania dla wszystkich znaków (w tym końcowego znaku kropki) tekstu wejściowego:
regex = .
input = The quick brown fox jumps over the lazy ox.
Found [T] starting at 0 and ending at 0
Found [h] starting at 1 and ending at 1
Found [e] starting at 2 and ending at 2
Found [ ] starting at 3 and ending at 3
Found [q] starting at 4 and ending at 4
Found [u] starting at 5 and ending at 5
Found [i] starting at 6 and ending at 6
Found [c] starting at 7 and ending at 7
Found [k] starting at 8 and ending at 8
Found [ ] starting at 9 and ending at 9
Found [b] starting at 10 and ending at 10
Found [r] starting at 11 and ending at 11
Found [o] starting at 12 and ending at 12
Found [w] starting at 13 and ending at 13
Found [n] starting at 14 and ending at 14
Found [ ] starting at 15 and ending at 15
Found [f] starting at 16 and ending at 16
Found [o] starting at 17 and ending at 17
Found [x] starting at 18 and ending at 18
Found [ ] starting at 19 and ending at 19
Found [j] starting at 20 and ending at 20
Found [u] starting at 21 and ending at 21
Found [m] starting at 22 and ending at 22
Found [p] starting at 23 and ending at 23
Found [s] starting at 24 and ending at 24
Found [ ] starting at 25 and ending at 25
Found [o] starting at 26 and ending at 26
Found [v] starting at 27 and ending at 27
Found [e] starting at 28 and ending at 28
Found [r] starting at 29 and ending at 29
Found [ ] starting at 30 and ending at 30
Found [t] starting at 31 and ending at 31
Found [h] starting at 32 and ending at 32
Found [e] starting at 33 and ending at 33
Found [ ] starting at 34 and ending at 34
Found [l] starting at 35 and ending at 35
Found [a] starting at 36 and ending at 36
Found [z] starting at 37 and ending at 37
Found [y] starting at 38 and ending at 38
Found [ ] starting at 39 and ending at 39
Found [o] starting at 40 and ending at 40
Found [x] starting at 41 and ending at 41
Found [.] starting at 42 and ending at 42
Cytuj metaznaki
Aby określić .lub dowolny inny metaznak jako znak dosłowny w konstrukcji wyrażenia regularnego, należy dokonać ucieczki przed nim w jeden z następujących sposobów:
  • poprzedź go znakiem odwrotnego ukośnika;
  • Umieść ten metaznak pomiędzy \Qi \E(na przykład \Q.\E).
Pamiętaj, aby zduplikować wszystkie znaki występujące w literale ciągu, takie jak String regex = "\\.";ukośniki odwrotne (na przykład \\.lub \\Q.\\E). Nie duplikuj tych ukośników odwrotnych, które są częścią argumentu wiersza poleceń.

Klasy postaci

Czasami musisz ograniczyć dopasowania, których szukasz, do określonego zestawu znaków. Na przykład przeszukaj tekst pod kątem samogłosek a, e, i , przy iczym każde wystąpienie litery samogłoski zostanie uznane za dopasowanie. W rozwiązywaniu takich problemów pomogą nam klasy znaków, które definiują zbiory znaków pomiędzy metaznakami nawiasów kwadratowych ( ). Klasa obsługuje proste klasy znaków, klasy zakresów, klasy odwrotności, sumy, przecięcia i odejmowania. Przyjrzymy się teraz wszystkim. ou[ ]Pattern

Proste klasy znaków

Prosta klasa znaków składa się ze znaków umieszczonych obok siebie i dopasowuje tylko te znaki. Na przykład klasa [abc]dopasowuje znaki ai b. cRozważmy następujący przykład: java RegexDemo [csw] cave Jak widać z wyników, w tym przykładzie tylko znak, cdla którego występuje dopasowanie w cave:
regex = [csw]
input = cave
Found [c] starting at 0 and ending at 0

Odwrócone klasy znaków

Odwrócona klasa znaków zaczyna się od metaznaku ^i dopasowuje tylko te znaki, które w niej nie występują. Na przykład klasa [^abc]dopasowuje wszystkie znaki z wyjątkiem a, bi c. Rozważmy następujący przykład: java RegexDemo "[^csw]" cave Zauważ, że w moim systemie operacyjnym (Windows) wymagane są podwójne cudzysłowy, ponieważ powłoka traktuje je ^jako znak ucieczki. Jak widać, w tym przykładzie znaleziono tylko znaki a, vi e, dla których znajdują się dopasowania w cave:
regex = [^csw]
input = cave
Found [a] starting at 1 and ending at 1
Found [v] starting at 2 and ending at 2
Found [e] starting at 3 and ending at 3

Klasy znaków zakresu

Klasa znaku zakresu składa się z dwóch znaków oddzielonych łącznikiem ( -). Wszystkie znaki, zaczynając od znaku po lewej stronie łącznika, a kończąc na znaku po prawej stronie, są częścią zakresu. Na przykład zakres [a-z]pasuje do wszystkich małych liter alfabetu łacińskiego. Jest to równoważne zdefiniowaniu prostej klasy [abcdefghijklmnopqrstuvwxyz]. Rozważmy następujący przykład: java RegexDemo [a-c] clown Ten przykład będzie pasował tylko do znaku c, który ma dopasowanie w clown:
regex = [a-c]
input = clown
Found [c] starting at 0 and ending at 0
Wyrażenia regularne w Javie, część 2 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