Reguläre Ausdrücke + logische Programmierung. Was ist das Ergebnis?

Hallo liebe Leser.

Reguläre Ausdrücke sind eine bekannte Sache, die in verschiedenen Projekten verwendet wird, meistens für nicht sehr komplizierte Fälle des Parsens strukturierter Texte. Auf den ersten Blick eine etwas andere Aufgabe wie die umgekehrte Synthese von Programmmodellen (wenn von einem System automatisch Programmcode gemäß einem Blockmodell des zu lösenden Problems generiert wird und das ursprüngliche Modell mithilfe dieses Codes neu erstellt werden muss) sowie die Programmierung von Programmmodellen mithilfe von Text Bei der Beschreibung der Aufgabe stieß ich auf das Problem, Texte zu analysieren oder vielmehr Textfragmente für einige benutzerdefinierte Vorlagen zu identifizieren. Ich wollte eine ziemlich einfache und flexible (anpassbare) Lösung. Reguläre Ausdrücke schienen im laufenden Betrieb nicht so zu sein, da selbst bei einer so einfachen Aufgabe wie dem Überprüfen eines Wortes in einem Wörterbuch leider eine sorgfältige Auflistung aller Optionen in diesem Ausdruck erforderlich war. Und sie haben keinen Analysebaum gebaut. Sie könnten jedoch deutlich verbessert werden. Dies wird diskutiert.

Also wurden folgende Aufgaben gestellt :

  1. Der reguläre Ausdruck sollte in der Lage sein, einen Analysebaum zu erstellen. Es ist erforderlich, Standardzugriffsmöglichkeiten für diesen Baum zu implementieren.
  2. Der reguläre Ausdruck sollte in der Lage sein, Überprüfungen gefundener Fragmente im Wörterbuch (genaue oder nicht strenge Entsprechung nach Levenshtein) sowie komplexere Überprüfungen mehrerer Tabellen gleichzeitig aufzunehmen.
  3. Zusätzlich zu den einfachen Prüfungen (oben aufgeführt) hätte ich gerne mehr Fuzzy-Prüfungen, zum Beispiel die Kompatibilität von Wörtern und Ausdrücken, ein neuronales Netzwerk

Baum analysieren.


In regulären Ausdrücken werden analysierte Fragmente durch die Anzahl der Klammern identifiziert. Dies ist, gelinde gesagt, unpraktisch, daher wurde eine Entscheidung über die Möglichkeit getroffen, die Klammern zu benennen. Übrigens sollten diese Namen im Analysebaum erscheinen. Die Syntax wurde einfach gewählt:

(_)->{_} 

Wenn nach Klammern im ursprünglichen Ausdruck ein Operator (*, + usw.) stand, "bewegte" er sich hinter die rechte Klammer. Zum Beispiel:

 (\w+\s)->{A}+ 

Nichts verhindert die Benennung und Klammern, zum Beispiel:

 ((\w+)->{ID}\s)->{A}+ 

Im letzten Beispiel generiert der geänderte reguläre Ausdruck einen Analysebaum mit einer bedingten Wurzel. Auf der nächsten Ebene gibt es Instanzen von A (es kann mehr als eine geben), auf der nächsten Ebene gibt es ID-Werte. Es ist bequem, mit XPath auf einen solchen Baum zuzugreifen, den ich implementiert habe. Eine solche Anfrage ist beispielsweise möglich:

 //A[2]/ID[text()!=""]/text() 

Wortprüfungen für Wörterbücher, Tabellen und ein einfaches neuronales Netzwerk


Das Parsen eines regulären Ausdrucks ist dem Parsen eines einfachen logischen Ausdrucks sehr ähnlich, beispielsweise in der Prolog-Sprache. Dies führt zu der Idee, dass Prolog-ähnliche Fragmente, die sein werden:

a) Ketten verschiedener Kontrollen. Dies ist nicht schwierig, zumal die Variablen bereits erschienen sind (in Form von benannten Klammern);
b) oder Auffüllen von Tabellen / Wörterbüchern mit erkannten Fragmenten;
c) oder Ausnahmen von den Tabellen / Wörterbüchern der erkannten Fragmente;
d) oder ein Team zur Erstellung / Schulung eines neuronalen Netzwerks.

Die allgemeine Syntax hier wäre:

 (_)_=>{1,2,...} 

operation_symbol hängt von der Operation ab: Überprüfung (?), Nachschub (+), Ausschluss (-), Erstellung / Schulung (*). Bei den Prädikaten werden der Name des Prädikats (Standard oder Ihr eigenes) und eine Liste seiner Parameter in Klammern angegeben. Parameter können Konstanten, Eingabevariablen, Ausgabevariablen (mit einem "$" -Zeichen vorangestellt), ein Vorzeichen eines beliebigen Werts "_" oder ein Verweis auf den aktuellen Wert des Ausdrucksfragments (einzelnes Zeichen "$") sein. Die Analyse eines solchen Ausdrucks wird als erfolgreich angesehen, wenn alle Prädikate in der Kette erfolgreich sind.

Zum Beispiel der Ausdruck:

 ([--]+)->{V1}\s+([--]+)->{V2}()?=>{check(V1},check(V2),correlate(V1,V2)} 

wählt zwei aufeinanderfolgende Wörter auf Russisch aus und fügt sie in die Variablen V1 und V2 ein. Anschließend werden diese Wörter mit der Prädikatprüfung (dies kann eine einfache Prüfung der Tabelle sein) und abschließend mit dem Prädikatkorrelat (es kann auch eine Prüfung der Tabelle erfolgen) überprüft. Die Art der Überprüfung (streng oder nicht streng) wird durch die Angabe des Prädikats bestimmt.

Wenn die Korrelationstabelle nicht die Wörter selbst enthält, sondern einige Wortcodes und ein Merkmal ihrer Kompatibilität, kann es einen solchen Ausdruck geben:

 ()->{C1}()->{C2}([--]+)->{check($,$C1}\s+([--]+)->{V2}()?=>{check(V2,$C2),correlate(C1,C2,1)} 

Hier werden zunächst zwei Variablen eingeführt, C1 und C2. Das Korrelatprädikat kann auch ein neuronales Netzwerk mit zwei Eingängen (Wortcodes) und einem Ausgang (Kompatibilität) sein, das gemäß einem vordefinierten oder dynamisch zusammengesetzten Satz (während der Operation mit regulären Ausdrücken) trainiert wird.

Es bleibt hinzuzufügen, dass spezielle Direktiven parallel und sequentiell auch als Prädikate angegeben werden können, die jeweils die Parallelität von Ausführungen in der Prädikatkette enthalten und berechnen (die in den Prädikatabhängigkeitsbaum konvertiert wird, nach dem sie parallelisiert wird). Darüber hinaus können Sie einen speziellen Modus aktivieren, in dem versucht wird, die Ausführungszeit einzelner Prädikate dynamisch vorherzusagen und zu entscheiden, ob die Parallelität wirksam ist oder umgekehrt, was nur zusätzliche Kosten verursacht.

Fazit


Alle beschriebenen Modifikationen regulärer Ausdrücke sind im Prototyp (Modifikation des Standards regexpr.pas) auf Free Pascal implementiert.

Ich hoffe, dass diese Ideen jemandem nützlich sein werden.

Mit solchen regulären logischen Ausdrücken + Programmierung auf einem reinen Prolog war es nun zum einen möglich, eine Ergänzung zum Programmerzeugungssystem zu schreiben, die das ursprüngliche Programmmodell aus dem zuvor von ihm generierten Code wiederherstellt, und zum anderen Elemente der natürlichen Sprache für dieses System zu erstellen Schnittstelle (die Erklärung des Problems wird in einer sehr vereinfachten russischen Sprache übernommen und darauf wird ein Modell des Problems formuliert, nach dem das Programm bereits generiert wurde).

Source: https://habr.com/ru/post/de415797/


All Articles