Jakie jest znaczenie Pattern.compile()
metody?
Dlaczego przed pobraniem Matcher
obiektu muszę skompilować ciąg wyrażenia regularnego ?
Na przykład :
String regex = "((\\S+)\\s*some\\s*";
Pattern pattern = Pattern.compile(regex); // why do I need to compile
Matcher matcher = pattern.matcher(text);
new Pattern(regex)
zamiast statycznej funkcji kompilującej. komentarz marcolopes jest na miejscu.Odpowiedzi:
compile()
Metoda nazywana jest zawsze w pewnym momencie; to jedyny sposób na stworzenie obiektu Pattern. Tak więc pytanie brzmi naprawdę, dlaczego miałbyś to nazwać wyraźnie ? Jednym z powodów jest to, że potrzebujesz odniesienia do obiektu Matcher, aby móc używać jego metod, takich jakgroup(int)
pobieranie zawartości grup przechwytywania. Jedynym sposobem na zdobycie obiektu Matcher jest użyciematcher()
metody obiektu Pattern , a jedynym sposobem na uzyskanie uchwytu obiektu Pattern jest użyciecompile()
metody. Następnie jestfind()
metoda, która w przeciwieństwie domatches()
klas String lub Pattern nie jest duplikowana.Innym powodem jest unikanie ciągłego tworzenia tego samego obiektu Pattern. Za każdym razem, gdy używasz jednej z metod opartych na wyrażeniach regularnych w łańcuchu (lub
matches()
metody statycznej we wzorcu), tworzy ona nowy wzorzec i nowy element dopasowujący. Więc ten fragment kodu:... jest dokładnie równoważne z tym:
Oczywiście robi to dużo niepotrzebnej pracy. W rzeczywistości skompilowanie wyrażenia regularnego i utworzenie wystąpienia obiektu Pattern może z łatwością zająć więcej czasu niż wykonanie rzeczywistego dopasowania. Dlatego zwykle ma sens wyciągnięcie tego kroku z pętli. Możesz również stworzyć Matchera z wyprzedzeniem, chociaż nie są one tak drogie:
Jeśli znasz wyrażenia regularne .NET, możesz się zastanawiać, czy
compile()
metoda Javy jest powiązana zRegexOptions.Compiled
modyfikatorem .NET ; odpowiedź brzmi nie.Pattern.compile()
Metoda Java jest po prostu odpowiednikiem konstruktora Regex platformy .NET. Po określeniuCompiled
opcji:... kompiluje wyrażenie regularne bezpośrednio do kodu bajtowego CIL, dzięki czemu może działać znacznie szybciej, ale przy znacznych kosztach przetwarzania wstępnego i wykorzystania pamięci - potraktuj to jako sterydy dla wyrażeń regularnych. Java nie ma odpowiednika; nie ma różnicy między wzorcem, który jest tworzony za kulisami,
String#matches(String)
a tym, który tworzysz jawniePattern#compile(String)
.(EDYCJA: Pierwotnie powiedziałem, że wszystkie obiekty .NET Regex są buforowane, co jest niepoprawne. Od czasu .NET 2.0 automatyczne buforowanie występuje tylko w przypadku metod statycznych, takich jak
Regex.Matches()
bezpośrednie wywołanie konstruktora Regex. Ref )źródło
reset
obiekt Matcher, który jest kiedykolwiek używany tylko przez jeden wątek na raz, aby zmniejszyć przydziały.Kompiluj analizuje wyrażenie regularne i tworzy reprezentację w pamięci . Koszt kompilacji jest znaczący w porównaniu z dopasowaniem. Jeśli używasz wzorca wielokrotnie , buforowanie skompilowanego wzorca będzie miało pewną wydajność.
źródło
Podczas kompilacji
Pattern
Java wykonuje pewne obliczenia, aby przyspieszyć wyszukiwanie dopasowań wString
s. (Buduje w pamięci reprezentację wyrażenia regularnego)Jeśli zamierzasz używać
Pattern
wielokrotnie, zobaczysz ogromny wzrost wydajności w porównaniu z tworzeniem zaPattern
każdym razem nowego .W przypadku użycia wzorca tylko raz, krok kompilacji wydaje się po prostu dodatkowym wierszem kodu, ale w rzeczywistości może być bardzo pomocny w ogólnym przypadku.
źródło
Matcher matched = Pattern.compile(regex).matcher(text);
. Ma to swoje zalety w porównaniu z wprowadzeniem pojedynczej metody: argumenty są skutecznie nazywane i jest oczywiste, jakPattern
rozłożyć na czynniki, aby uzyskać lepszą wydajność (lub podzielić na metody).Jest to kwestia wydajności i wykorzystania pamięci, skompiluj i zachowaj zgodny wzorzec, jeśli chcesz go często używać. Typowym zastosowaniem wyrażenia regularnego jest walidacja danych wejściowych użytkownika (format) , a także formatowanie danych wyjściowych dla użytkowników , w tych klasach, zapisywanie zgodnego wzorca, wydaje się całkiem logiczne, ponieważ zwykle nazywali dużo.
Poniżej znajduje się przykładowy walidator, który naprawdę nazywa się dużo :)
Jak wspomniał @Alan Moore, jeśli masz w kodzie wyrażenie regularne wielokrotnego użytku (na przykład przed pętlą), musisz skompilować i zapisać wzorzec do ponownego wykorzystania.
źródło
Pattern.compile()
pozwalają na wielokrotne użycie wyrażenia regularnego (jest bezpieczne dla wątków). Korzyść z wydajności może być dość znacząca.Zrobiłem szybki test porównawczy:
compileOnce był od 3x do 4x szybszy . Myślę, że w dużym stopniu zależy to od samego wyrażenia regularnego, ale w przypadku często używanego wyrażenia regularnego wybieram rozszerzenie
static Pattern pattern = Pattern.compile(...)
źródło
Wstępne kompilowanie wyrażenia regularnego zwiększa szybkość. Ponowne użycie Matchera daje kolejne niewielkie przyspieszenie. Jeśli metoda jest wywoływana często, powiedzmy, że jest wywoływana w pętli, ogólna wydajność z pewnością wzrośnie.
źródło
Podobnie jak „Pattern.compile” istnieje „RECompiler.compile” [z com.sun.org.apache.regexp.internal], gdzie:
1. skompilowany kod wzorca [az] zawiera „az”
2. skompilowany kod dla wzorzec [0-9] zawiera '09'
3. skompilowany kod wzorca [abc] zawiera 'aabbcc'.
Zatem skompilowany kod jest świetnym sposobem na uogólnienie wielu przypadków. Dlatego zamiast mieć różne sytuacje obsługi kodu 1, 2 i 3. Problem sprowadza się do porównania z ascii obecnego i następnego elementu w skompilowanym kodzie, stąd pary. Zatem
a. wszystko z ascii między a i z jest między a i z
b. wszystko z ascii między „a” jest zdecydowanie „a”
źródło
Klasa Pattern jest punktem wejścia silnika regex i można jej używać poprzez Pattern.matches () i Pattern.comiple (). # Różnica między tymi dwoma. match () - aby szybko sprawdzić, czy tekst (String) pasuje do podanego wyrażenia regularnego comiple () - utwórz odniesienie do Pattern. Więc może użyć wiele razy, aby dopasować wyrażenie regularne do wielu tekstów.
Na przykład:
źródło