Ikegami odbędzie się wykładniczy przestrzeń do przechowywania ciąg zanim zostanie on przekształcony regex (pojawi się każde słowo 2 n - 1 razy, gdzie n jest liczbą słów, więc całkowita powierzchnia wynosi co najmniej 2 n - 1 * Suma (długość słów)). Jest to nie związane z silnikiem regex - ponieważ problem występuje przed przekształceniem ciągu w wyrażenie regularne.
równoważną budowa regex (w perspektywie zestawu strun że pasuje) do roztworu Ikegami byłoby:
^(?=[^ ])(?:(?: |^)John(?= |\z))?+(?:(?: |^)Von(?= |\z))?+(?:(?: |^)Neumann(?= |\z))?+\z
To zajmuje tylko przestrzeń liniową, w okresie obowiązywania liczby słów i całkowita długość wszystkich słów.
Dla jasności:
^
(?=[^ ])
(?:(?: |^)John(?= |\z))?+
(?:(?: |^)Von(?= |\z))?+
(?:(?: |^)Neumann(?= |\z))?+
\z
Spojrzenie wyprzedzeniem twierdzenie (?=[^ ])
ma 2 cele: zapobieganie pusty łańcuch przed dopasowane i upewnij się, że pierwszy znak nie jest spacja.
Zanotuj ?+
, co sprawia, że kwantyfikator zaborczy (lub atomowy), ponieważ nie musimy backtracking tutaj. Dlaczego? Jeśli mielibyśmy to zrobić normalnie, przejdziemy przez listę słów i porównamy je z lewym słowem na wejściu. Po znalezieniu dopasowania, kontynuujemy pętlę, aby porównać ją z następnym słowem na wejściu, dopóki wszystkie słowa w danych wejściowych nie zostaną znalezione lub skończyliśmy zapętlać listę słów.
Kwantyfikator dzierżawy o wartościrównież zapobiega powstawaniu piekła wstecznego. Jeśli słowo zostanie uznane za dopasowanie, nigdy nie zostanie ponownie rozpatrzone.
Dla każdego słowa można je poprzedzić spacją lub jest początkiem ciągu. Twierdzenie wyprzedzające o numerze (?= |\z)
ma na celu upewnienie się, że słowa z tym samym prefiksem nie zostaną niepoprawnie dopasowane przy pierwszym podejściu (np. "John Von Vone"
, spróbuj dopasować "John Vone"
).
Ponieważ nie ma wstecznego śledzenia, najgorszy przypadek jest liniowy pod względem długości wszystkich słów i długości wprowadzanego ciągu znaków (tak samo, jak można to zrobić bez wyrażeń regularnych).
Możemy zmienić regex trochę, aby umożliwić elastyczne rozstaw
^(?= *+[^ ])(?: *+John(?= |\z))?+(?: *+Von(?= |\z))?+(?: *+Neumann(?= |\z))?+ *+\z
Dla jasności (prowadzące przestrzeń jest istotne):
^
(?= *+[^ ])
(?: *+John(?= |\z))?+
(?: *+Von(?= |\z))?+
(?: *+Neumann(?= |\z))?+
*+
\z
Spojrzenie wyprzedzeniem (?= *+[^ ])
u Początek sprawia, że ciąg wejściowy nie zawiera tylko spacji.
Wyrażenie regularne zostaje zmienione, aby dozwolona była jakakolwiek ilość spacji przed słowem (wycofanie zabronione przez kwantyfikator dzierżawczy). Zastosowano 0 lub więcej kwantyfikatorów *
, dla przypadku, gdy słowo znajduje się na samym początku łańcucha. Nie ma szans, aby zderzyły się 2 słowa, ze względu na stwierdzenie wyprzedzające (?= |\z)
.
Ciągle zajmuje liniową przestrzeń podczas konstruowania napisu (przed wprowadzeniem go do silnika regex). Najgorsza wydajność jest również liniowa.
skrajnych przypadkach
Oryginalne słów:
aaaaaaaaaaaaaaaaaaa0 aaaaaaaaaaaaaaaaaaa1 ... aaaaaaaaaaaaaaaaaaa9 aaaaaaaaaaaaaaaaaaaa ... aaaaaaaaaaaaaaaaaaaz aaaaaaaaaaaaaaaaaaaA ... aaaaaaaaaaaaaaaaaaaZ
(Każde słowo jest 20 znaków, ostatnich zmian postać z 0-9
, potem a-z
, następnie A-Z
)
Struny do wyszukiwania (nie pasujące):
aaaaaaaaaaaaaaaaaaaz aaaaaaaaaaaaaaaaaaay
(y
może przyjść tylko przed z
)
Oryginalny słowo:
patterns used in Perl pattern matching evolved from those supplied
(Niektóre normalne słowa)
Ciągi do wyszukiwania (nie pasujące):
patterns used in Perl pattern matching evolved from those suppliedd
(Extra d
na końcu)
Oryginalny słowo:
aaaaaaaaaaaa aaaaaaaaaaa aaaaaaaaaa aaaaaaaaa aaaaaaaa aaaaaaa aaaaaa aaaaa aaaa
(. Słowo zawiera tylko a
, o różnej długości)
Struny do poszukiwania (nie pasujące):
aaaaaaaaaaaa aaaaaaaaaaa aaaaaaaaaa aaaaaaaaa aaaaaaaa aaaaaaa aaaaaa aaaaa aaaaa
(Dodatkowe a
na końcu)
Oryginalny słowo:
performance abc xyz performance 456 [email protected]# performance
(samo słowo pojawia się wielokrotnie)
Struny do wyszukiwania (nie pasujące):
performance performance performance performance
@ogzd wysłany '/^(? =.) (?: \ Bjohn \ b)? \ S * (?: \ Bvon \ b)? \ S * (?: \ Bneumann \ b)? \ Z/i' (z pewną pomocą). Nie jestem pewien, dlaczego to usunął. Nie jest to rozwiązanie uniwersalne, ale OP może nie wymagać rozwiązania ogólnego. – ikegami
@ikegami: '(? =.)' Musi być '(? = \ S)' w przeciwnym razie wzorzec dopasuje ciąg białych znaków. – Borodin