1. Definieren des Problems
Da nicht klar ist, was ausgegeben werden soll, wenn der gesamte String nicht dem Muster K*
entspricht, werde ich das Problem neu definieren, um klarzustellen, was in einem solchen Fall ausgegeben werden soll.
Gegeben ein beliebiges Muster K:
- Überprüfen Sie, ob der String dem Muster
K*
entspricht.
- Wenn der String das Muster
K*
hat, dann wird der String in nicht überlappende Tokens aufgeteilt, die zu K passen.
- Wenn der String nur ein Präfix hat, das dem Muster
K*
entspricht, dann wählen Sie das Präfix aus, das von K*+
1 gewählt wurde, und teilen Sie das Präfix in Tokens auf, die zu K passen.
1 Ich weiß nicht, ob es eine Möglichkeit gibt, das längste Präfix zu erhalten, das zu K passt. Natürlich können Sie immer das letzte Zeichen nacheinander entfernen und gegen K*
testen, bis es passt, aber das ist offensichtlich ineffizient.
Wenn nicht anders angegeben, wird alles, was ich unten schreibe, meiner obigen Problembeschreibung folgen. Beachten Sie, dass der 3. Punkt des Problems die Unklarheit darüber lösen soll, welches Präfix-String genommen werden soll.
2. Wiederholte Erfassungsgruppe in .NET
Das oben beschriebene Problem kann gelöst werden, wenn wir die Lösung für das Problem haben:
Gegeben ein Muster (K)*
, das eine wiederholte Erfassungsgruppe ist, erhalten Sie den erfassten Text für alle Wiederholungen, anstatt nur für die letzte Wiederholung.
- Im Fall, dass der String das Muster
K*
hat, indem er gegen ^(K)*$
abgeglichen wird, können wir alle Tokens erhalten, die zum Muster K
passen.
- Im Fall, dass der String nur ein Präfix hat, das zum Muster
K*
passt, durch Abgleichen gegen ^(K)*
, können wir alle Tokens erhalten, die zum Muster K
passen.
Dies ist der Fall bei .NET Regex, da es den gesamten erfassten Text für eine wiederholte Erfassungsgruppe behält.
Da wir jedoch Java verwenden, haben wir keinen Zugriff auf eine solche Funktion.
3. Lösung in Java
Die Überprüfung, ob der String das Muster K*
hat, kann immer mit Matcher.matches()
/String.matches()
durchgeführt werden, da der Motor das gesamte Eingabemuster vollständig zurückverfolgt, um auf irgendeine Weise K*
mit dem Eingabestring zu "vereinheitlichen". Schwierig ist es jedoch, den Eingabestring in Tokens aufzuteilen, die zum Muster K
passen.
Wenn K*
äquivalent zu K*+
ist
Wenn das Muster K die Eigenschaft hat:
Für alle Zeichenfolgen2 ist K*
äquivalent zu K*+
, d.h. wie der Eingabestring in Tokens aufgeteilt wird, die zum Muster K
passen, ist das Gleiche.
2 Sie können diese Bedingung nur für die Eingabestrings definieren, auf denen Sie arbeiten, aber sicherstellen, dass diese Vorbedingung erfüllt ist, ist nicht einfach. Wenn Sie es für alle Zeichenfolgen definieren, müssen Sie nur Ihren Regex analysieren, um zu überprüfen, ob die Bedingung erfüllt ist oder nicht.
Dann kann eine Lösung konstruiert werden, die das Problem in einem Durchgang löst. Sie können Matcher.find()
wiederholt auf das Muster \GK
anwenden und überprüfen, ob das letzte gefundene Übereinstimmung direkt am Ende des Strings steht. Dies ähnelt Ihrer aktuellen Lösung, nur dass Sie die Randüberprüfung mit Code durchführen.
Das +
nach dem Quantifizierer *
in K*+
macht den Quantifizierer possessiv. Ein possessiver Quantifizierer verhindert das Zurückverfolgen des Motors, was bedeutet, dass jede Wiederholung immer die erste mögliche Übereinstimmung für das Muster K ist. Diese Eigenschaft benötigen wir, damit die Lösung \GK
äquivalente Bedeutung hat, da sie auch die erste mögliche Übereinstimmung für das Muster K zurückgibt.
Wenn K*
NICHT äquivalent zu K*+
ist
Ohne die oben genannte Eigenschaft benötigen wir 2 Durchgänge, um das Problem zu lösen. Erster Durchgang, um Matcher.matches()
/String.matches()
auf das Muster K*
anzuwenden. Im zweiten Durchgang:
-
Wenn der String nicht dem Muster K*
entspricht, verwenden wir wiederholt Matcher.find()
auf das Muster \GK
, bis keine Übereinstimmung mehr gefunden werden kann. Dies kann aufgrund der Definition, welches Präfix-String zu nehmen ist, wenn der Eingabestring nicht zum Muster K*
passt, erreicht werden.
-
Wenn der String dem Muster K*
entspricht, wiederholen Sie die Verwendung von Matcher.find()
auf das Muster \GK(?=K*$)
. Dies führt jedoch zu redundanter Arbeit beim Abgleichen des Rests des Eingabestrings.
Beachten Sie, dass diese Lösung universell für jedes K anwendbar ist. Mit anderen Worten, sie gilt auch für den Fall, dass K*
äquivalent zu K*+
ist (aber für diesen Fall werden wir die bessere Ein-Pass-Lösung verwenden).