Prüfe, ob eine Regex eine andere Regex abdeckt

8

Ich versuche, einen Textclusteralgorithmus zu implementieren. Der Algorithmus gruppiert ähnliche Zeilen von Rohtext, indem er sie durch Regex ersetzt, und aggregiert die Anzahl von Mustern, die zu jedem Regex passen, um eine saubere Zusammenfassung des Eingabetextes bereitzustellen, anstatt sich wiederholende Muster aus dem Eingabetext zu zeigen. Bei diesem Versuch bin ich auf die Notwendigkeit gestoßen, herauszufinden, ob eine Regex eine andere abdeckt.

Nehmen wir an, wir sind nur über reguläre Ausdrücke mit '*' und '+' Wildcards betroffen, dh '*' bedeutet null oder mehr Vorkommen eines Alphabets und '+' bedeutet 1 oder mehr Vorkommen eines Alphabets. Nimm auch an, dass der Zeichensatz ASCII ist.

Zum Beispiel:

%Vor%

Im Grunde suche ich nach einer effizienten Implementierung der folgenden Methode, die angibt, ob strA (kann eine Regex enthalten) für strB (enthält möglicherweise eine Regex) abdeckt. Beachten Sie, dass es auch eine Möglichkeit geben sollte, den Regex-Zeichen '*' und '+' in den Eingabezeichenfolgen strA und strB zu entgehen.

Methodensignatur in C ++:

%Vor%

Ich denke, dass für die Implementierung ein rekursiver Ansatz erforderlich ist, der ein wenig kompliziert sein kann. Aber ich bin neugierig zu wissen, ob ich vorhandene Implementierungen wiederverwenden kann, anstatt das Rad neu zu erfinden oder ob es andere einfache Möglichkeiten gibt, dies zu tun.

    
Kowshik 27.03.2012, 10:42
quelle

4 Antworten

4

Angesichts der einfachen Regex-Grammatik, die Sie vorschlagen, ist die Lösung ziemlich trivial.

Nehmen Sie Ihr komplexeres Beispiel, A+M+BC* covers AMM+B+C+M+BC* Sie können es als A{1,}M{1,}B{1,1}C{0,} cover A{1,1}M{2,}B{1,}C{1,}M{1,}B{1,1}C{0,}

umschreiben

Dies führt uns zu der einfachen Regel: R1 deckt R2 ab, wenn alle Symbole in der gleichen Reihenfolge erscheinen, alle unteren Grenzen von R1 kleiner oder gleich denen von R2 sind und die oberen Grenzen von R1 sind mehr oder gleich denen von R2 .

Jetzt gibt es ein kleines Problem mit der einfachen Regel. AB*C deckt AC ab, d. h. es besteht die Möglichkeit, dass ein optionales Symbol in R1 und nicht in R2 angezeigt wird. Sie können das lösen, indem Sie ein {0,0} in R2 einfügen, wenn in R1 ein (optionales) Symbol steht, das nicht in der entsprechenden Position in R2 erscheint. Z.B. AB*C deckt AB{0,0}C ab.

Die Regel "optionales Symbol" ist eine Optimierung. Wenn das Symbol in R1 nicht optional ist, deckt R1 sicher nicht R2 ab. Z.B. AB+C deckt AC nicht ab. Daher muss kein B{0,0} eingefügt werden. Aber wenn Sie das tun, sehen Sie, dass A{1,1}B{1,}C{1,1} nicht A{1,1}B{0,0}C{1,1} abdeckt, da die untere Grenze von R1 für B (1) mehr ist als die R2 untere Grenze für B (0)

    
MSalters 27.03.2012 11:27
quelle
2

Ich würde so etwas wie das Implementieren einer Funktion zum Finden des minimalen DFA aus einem gegebenen Regulären Ausdruck tun. Nehmen wir an, dass

DFA GetMinimalDFA (Regex r1) macht das.

%Vor%     
Blim 27.03.2012 10:53
quelle
2

In Perl wäre das ziemlich einfach. Der erste Schritt besteht darin, jeden Regex zu normalisieren, indem Sie A+ in AA* , A*A in AA* und A*A* in A* :

ändern %Vor%

Schritt zwei besteht darin, die erste Regex von einer Regex, die den Strings selbst entspricht, in eine Perl-Regex zu konvertieren, die mit den normalisierten Regexen übereinstimmt, die diesen Strings entsprechen; Zum Beispiel wird AA*B in ^AA*\*?B$ konvertiert, was "String-Anfang" bedeutet, gefolgt von A gefolgt von null oder mehr As, optional gefolgt von einem Sternchen gefolgt von B gefolgt von einem String-Ende ":

%Vor%

Schritt drei braucht keine Erklärung:

%Vor%

Dies gibt einen wahren Wert für Ihre Fälle # 1-3 zurück. Es gibt jedoch einen falschen Wert für Ihren Fall Nr. 4 zurück, da A+M+BC* nicht für AMM+B+C+M+BC* ?

gilt, es sei denn, mir fehlt etwas
  

Beachten Sie, dass es auch eine Möglichkeit geben sollte, den Regex-Zeichen '*' und '+' in den Eingabezeichenfolgen strA und strB zu entgehen.

Ich habe mir im obigen Code keine Gedanken darüber gemacht, aber da Sie sich nur um ASCII sorgen, könnte ein Vorverarbeitungsschritt \* bedeuten * , \+ bedeutet + und \ bedeuten \ , indem sie in einzelne Zeichen außerhalb des ASCII-Bereichs übersetzt werden:

%Vor%

(obwohl das offensichtlich ziemlich haschisch ist).

In C ++ können Sie den gleichen Ansatz verwenden - es gibt Bibliotheken, die alle notwendigen Funktionen von Perl-Regexes implementieren - obwohl es natürlich etwas mehr Arbeit wäre.

    
ruakh 27.03.2012 23:35
quelle
0

Überprüfen Sie diese Perl-Modul-Quelle , aber denken Sie daran, dass dies der Fall wäre funktioniert nicht für alle Regexps (da es das Problem lösen löst.

    
neutrinus 27.03.2012 10:50
quelle