Java Language
Wyrażenia regularne
Szukaj…
Wprowadzenie
Wyrażenie regularne to specjalna sekwencja znaków, która pomaga w dopasowywaniu lub znajdowaniu innych ciągów lub zestawów ciągów, przy użyciu specjalnej składni utrzymywanej we wzorcu. Java obsługuje obsługę wyrażeń regularnych za pośrednictwem pakietu java.util.regex
. Ten temat ma na celu wprowadzenie i pomoc deweloperom w lepszym zrozumieniu dzięki przykładom użycia wyrażeń regularnych w Javie.
Składnia
- Pattern patternName = Pattern.compile (regex);
- Matcher matcherName = patternName.matcher (textToSearch);
- matcherName.matches () // Zwraca true, jeśli textToSearch dokładnie pasuje do wyrażenia regularnego
- matcherName.find () // Przeszukuje textToSearch w poszukiwaniu pierwszej instancji podłańcucha pasującego do wyrażenia regularnego. Kolejne wywołania przeszukają resztę ciągu.
- matcherName.group (groupNum) // Zwraca podciąg wewnątrz grupy przechwytywania
- matcherName.group (nazwa_grupy) // Zwraca podciąg wewnątrz nazwanej grupy przechwytywania (Java 7+)
Uwagi
Import
Aby móc korzystać z Regex, musisz dodać następujący import:
import java.util.regex.Matcher
import java.util.regex.Pattern
Pułapki
W Javie odwrotny ukośnik jest poprzedzany podwójnym odwrotnym ukośnikiem, więc odwrotny ukośnik w łańcuchu wyrażeń regularnych powinien być wprowadzony jako podwójny odwrotny ukośnik. Jeśli musisz uciec przed podwójnym ukośnikiem odwrotnym (aby dopasować pojedynczy ukośnik odwrotny do wyrażenia regularnego, musisz wprowadzić go jako poczwórny ukośnik odwrotny).
Ważne symbole wyjaśnione
Postać | Opis |
---|---|
* | Dopasuj poprzedni znak lub podwyrażenie 0 lub więcej razy |
+ | Dopasuj poprzedni znak lub podwyrażenie 1 lub więcej razy |
? | Dopasuj poprzedni znak lub podwyrażenie 0 lub 1 razy |
Dalsza lektura
Temat wyrażenia regularnego zawiera więcej informacji o wyrażeniach regularnych.
Korzystanie z grup przechwytywania
Jeśli chcesz wyodrębnić część ciągu z ciągu wejściowego, możemy użyć grup przechwytywania wyrażeń regularnych.
W tym przykładzie zaczniemy od prostego wyrażenia regularnego numeru telefonu:
\d{3}-\d{3}-\d{4}
Jeśli nawiasy zostaną dodane do wyrażenia regularnego, każdy zestaw nawiasów jest uważany za grupę przechwytującą . W tym przypadku używamy tak zwanych numerowanych grup przechwytywania:
(\d{3})-(\d{3})-(\d{4})
^-----^ ^-----^ ^-----^
Group 1 Group 2 Group 3
Zanim będziemy mogli go używać w Javie, nie możemy zapominać o przestrzeganiu reguł Ciągów, unikając ukośników odwrotnych, co powoduje następujący wzorzec:
"(\\d{3})-(\\d{3})-(\\d{4})"
Najpierw musimy skompilować wzorzec regularny, aby utworzyć Pattern
a następnie potrzebujemy Matcher
aby dopasować nasz ciąg wejściowy do wzorca:
Pattern phonePattern = Pattern.compile("(\\d{3})-(\\d{3})-(\\d{4})");
Matcher phoneMatcher = phonePattern.matcher("abcd800-555-1234wxyz");
Następnie Matcher musi znaleźć pierwszą podsekwencję pasującą do wyrażenia regularnego:
phoneMatcher.find();
Teraz, korzystając z metody grupy, możemy wyodrębnić dane z ciągu:
String number = phoneMatcher.group(0); //"800-555-1234" (Group 0 is everything the regex matched)
String aCode = phoneMatcher.group(1); //"800"
String threeDigit = phoneMatcher.group(2); //"555"
String fourDigit = phoneMatcher.group(3); //"1234"
Uwaga: Matcher.group()
może być użyty zamiast Matcher.group(0)
.
Java 7 wprowadziła nazwane grupy przechwytywania. Nazwane grupy przechwytywania działają tak samo jak ponumerowane grupy przechwytywania (ale z nazwą zamiast liczby), chociaż występują niewielkie zmiany składniowe. Korzystanie z nazwanych grup przechwytywania poprawia czytelność.
Możemy zmienić powyższy kod, aby użyć nazwanych grup:
(?<AreaCode>\d{3})-(\d{3})-(\d{4})
^----------------^ ^-----^ ^-----^
AreaCode Group 2 Group 3
Aby uzyskać zawartość „AreaCode”, możemy zamiast tego użyć:
String aCode = phoneMatcher.group("AreaCode"); //"800"
Używanie wyrażenia regularnego z niestandardowym zachowaniem poprzez kompilację Wzorca z flagami
Pattern
można skompilować z flagami, jeśli wyrażenie regularne jest używane jako dosłowny String
, użyj wbudowanych modyfikatorów:
Pattern pattern = Pattern.compile("foo.", Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
pattern.matcher("FOO\n").matches(); // Is true.
/* Had the regex not been compiled case insensitively and singlelined,
* it would fail because FOO does not match /foo/ and \n (newline)
* does not match /./.
*/
Pattern anotherPattern = Pattern.compile("(?si)foo");
anotherPattern.matcher("FOO\n").matches(); // Is true.
"foOt".replaceAll("(?si)foo", "ca"); // Returns "cat".
Escape Characters
Ogólnie
Aby użyć znaków specyficznych dla wyrażeń regularnych ( ?+|
Itd.) W ich dosłownym znaczeniu, należy je usunąć. W powszechnym wyrażeniu regularnym odbywa się to odwrotnym ukośnikiem \
. Ponieważ jednak ma on specjalne znaczenie w ciągach Java, należy użyć podwójnego ukośnika odwrotnego \\
.
Te dwa przykłady nie będą działać:
"???".replaceAll ("?", "!"); //java.util.regex.PatternSyntaxException
"???".replaceAll ("\?", "!"); //Invalid escape sequence
Ten przykład działa
"???".replaceAll ("\\?", "!"); //"!!!"
Dzielenie ciągu rozdzielanego rurami
To nie zwraca oczekiwanego wyniku:
"a|b".split ("|"); // [a, |, b]
Zwraca oczekiwany wynik:
"a|b".split ("\\|"); // [a, b]
Ucieczka ukośnikiem \
To da błąd:
"\\".matches("\\"); // PatternSyntaxException
"\\".matches("\\\"); // Syntax Error
To działa:
"\\".matches("\\\\"); // true
Dopasowanie do wyrażenia regularnego.
Jeśli potrzebujesz dopasować znaki, które są częścią składni wyrażeń regularnych, możesz zaznaczyć całość lub część wzorca jako literał wyrażenia regularnego.
\Q
oznacza początek literału regularnego. \E
oznacza koniec literału regularnego.
// the following throws a PatternSyntaxException because of the un-closed bracket
"[123".matches("[123");
// wrapping the bracket in \Q and \E allows the pattern to match as you would expect.
"[123".matches("\\Q[\\E123"); // returns true
Łatwiejszym sposobem na zrobienie tego bez konieczności pamiętania sekwencji specjalnych \Q
i \E
jest użycie Pattern.quote()
"[123".matches(Pattern.quote("[") + "123"); // returns true
Nie pasuje do podanego ciągu
Aby dopasować coś, co nie zawiera określonego ciągu, można użyć ujemnego lookahead:
Składnia wyrażenia regularnego: (?!string-to-not-match)
Przykład:
//not matching "popcorn"
String regexString = "^(?!popcorn).*$";
System.out.println("[popcorn] " + ("popcorn".matches(regexString) ? "matched!" : "nope!"));
System.out.println("[unicorn] " + ("unicorn".matches(regexString) ? "matched!" : "nope!"));
Wynik:
[popcorn] nope!
[unicorn] matched!
Dopasowywanie ukośnika odwrotnego
Jeśli chcesz dopasować odwrotny ukośnik w wyrażeniu regularnym, musisz uciec.
Odwrotny ukośnik jest znakiem ucieczki w wyrażeniach regularnych. Możesz użyć „\\”, aby odnieść się do pojedynczego ukośnika odwrotnego w wyrażeniu regularnym.
Jednak odwrotny ukośnik jest także znakiem ucieczki w dosłownym łańcuchu Java. Aby wyrażenie regularne z ciągiem znaków, trzeba uciec każdy z jego ukośniki. W ciągu można użyć literału „\\\\”, aby utworzyć wyrażenie regularne z „\\”, które z kolei może pasować do „\”.
Na przykład rozważ dopasowanie pasujących ciągów, takich jak „C: \ dir \ myfile.txt”. Wyrażenie regularne ([A-Za-z]):\\(.*)
Będzie pasować i zapewni literę dysku jako grupę przechwytującą. Zwróć uwagę na podwójny ukośnik odwrotny.
Aby wyrazić ten wzorzec za pomocą literału Java, każdy odwrotny ukośnik w wyrażeniu regularnym musi być poprzedzony znakami ucieczki.
String path = "C:\\dir\\myfile.txt";
System.out.println( "Local path: " + path ); // "C:\dir\myfile.txt"
String regex = "([A-Za-z]):\\\\.*"; // Four to match one
System.out.println("Regex: " + regex ); // "([A-Za-z]):\\(.*)"
Pattern pattern = Pattern.compile( regex );
Matcher matcher = pattern.matcher( path );
if ( matcher.matches()) {
System.out.println( "This path is on drive " + matcher.group( 1 ) + ":.");
// This path is on drive C:.
}
Jeśli chcesz dopasować dwa ukośniki odwrotne, będziesz używać ósemki w dosłownym ciągu, aby reprezentować cztery w wyrażeniu regularnym, aby dopasować dwa.
String path = "\\\\myhost\\share\\myfile.txt";
System.out.println( "UNC path: " + path ); // \\myhost\share\myfile.txt"
String regex = "\\\\\\\\(.+?)\\\\(.*)"; // Eight to match two
System.out.println("Regex: " + regex ); // \\\\(.+?)\\(.*)
Pattern pattern = Pattern.compile( regex );
Matcher matcher = pattern.matcher( path );
if ( matcher.matches()) {
System.out.println( "This path is on host '" + matcher.group( 1 ) + "'.");
// This path is on host 'myhost'.
}