2009-04-24 10 views
4

Ich würde gerne in der Lage sein, die Menge aller Zeichen zu berechnen, die als ersten Zeichen in einer Zeichenfolge durch eine gegebene Instanz java.util.regex.Pattern übereinstimmen können. Formal ausgedrückt, möchte ich angesichts der DFA, die einem bestimmten regulären Ausdruck entspricht, die Menge aller ausgehenden Übergänge vom Startzustand erhalten.Kann ich die Menge der ersten durch das Regex-Muster angepassten Zeichen bestimmen?

Ein Beispiel:

Pattern p = Pattern.compile("[abc]def|daniel|chris|\\s+"); 
Set<Character> first = getFirstSet(p); 

Das Set first folgende Elemente enthalten:

{ 'a', 'b', 'c', 'd', ' ', '\n', '\r', '\t' } 

Irgendwelche Ideen? Ich bin mir bewusst, dass ich das DFA selbst konstruieren und die relevanten Zustände auf diese Weise bestimmen kann, aber ich möchte diese Art von Ärger vermeiden (lies: es ist mir nicht so viel wert). Beachten Sie, dass meine Sprache Scala ist, also habe ich Zugriff auf alle Scala-Bibliotheken (was es wert ist).

Antwort

4

Ich denke, Sie könnten den regulären Ausdruck analysieren und eine rekursive Funktion definieren, die auf den geparsten regulären Ausdruck von links nach rechts wirkt und so eine Reihe von Erstaufträgen erstellt.

Manche Dinge sind einfach:

  • Reihenfolge: zuerst (R1R2) = erste (r 1) + (wenn '' in dem ersten (R1) ersten (r2) sonst leere Menge)
  • Makel: Erster (r1 | r2) = erste (r1) + erste (r2)
  • Iteration: erste (r *) = erste (r) + ''
  • Zeichen: erste (c) = c
  • Characterclasses: erste ([c1-cn]) = gesetzt (c1, c2, ..., cn) ...

Erweitern Sie dies auf alle Grundformen und Spezialflaggen, die Ihr regulärer Ausdruck Dialekt kennt, und Sie sind gut zu gehen.

+0

Ja, ich habe darüber nachgedacht. Dies wäre praktisch dasselbe wie das Erstellen des Front-Ends des DFA selbst.Vielleicht werde ich das tun, wenn es darauf ankommt, aber ich würde lieber eine einfachere Lösung finden. –

+0

Ich bin nicht sicher, wie viel einfacher es wird, als es zu analysieren (nach einer festen Grammatik aus dem Sprachstandard) und einige ziemlich offensichtliche Rekursionen, aber vielleicht ist das nur meine Compiler-Konstruktion infundiert Gehirn – Tetha

+0

Nun, Parsing und dann rekursive Traversal aren Schade, ich bin einfach nicht glücklich darüber, Java's Regular Expression Semantics replizieren zu müssen, nur um ein FIRST-Set zu bekommen. –

1

Man könnte es rekursiv lösen ...

  • Streifen Klammer der umschließenden und rekursiven nennen.
  • Auf Toplevel-Alternativen aufteilen und für jeden Teil rekursiv aufrufen.
  • Wenn es keine Alternativen gibt,
    • Ausgang alle Symbole von links bis zu dem optionalen Symbol zuerst keines beginnen.
    • Wenn es Gruppen gibt, geben Sie alle Symbole aus.

Es gibt wahrscheinlich viele Fehler in dieser Idee, aber das ist, was würde ich versuchen. Sie müssen Behauptung, Gruppennamen und tausend andere Dinge ausstreifen. Und wenn Sie eine umgekehrte Zeichenklasse wie [^ 0-9] finden, müssen Sie viele Zeichen ausgeben.

Also ich nehme an, es ist wirklich ein komplexes Problem.

+0

Ich hatte nicht über Negations-Klassen nachgedacht. Wenn man bedenkt, dass Java UTF-8 verwendet, könnte das FIRST-Set eine Größe von Hunderttausenden haben. Autsch! Vielleicht nehme ich einfach an, dass ein regulärer Ausdruck alles zusammenpassen kann und es nicht optimiert lässt ... –

+0

Ich dachte gerade darüber nach, den Ausdruck neu zu schreiben - wenn Sie einen Ausdruck erstellen könnten, der nur dem ersten Symbol des Eingabeausdrucks entspricht, könnten Sie eine Schleife durchlaufen einige einzelne Symbolzeichenfolgen und testen, ob der abgeleitete Ausdruck übereinstimmt. Aber um alle Zeichen zu erhalten, müssten Sie den ganzen Zeichensatz durchlaufen - viel Arbeit für Unicode. Und ich kann mir keine Methode vorstellen, um einen solchen abgeleiteten Ausdruck zu erhalten. Vielleicht hacken Sie sich in die Regex-Implementierung und untersuchen den internen Zustand durch Reflektion. –

+0

Aber all dies würde wahrscheinlich zum Schreiben einer Regex-Implementierung kommen. Also ich habe keine (guten) Ideen. –