CompactaEVE und Matching-Semantik
CompactaEVE ist die knappe kompilierte Form der EVE-Sprache und die Eingabe, die der Muster-Compiler tatsächlich analysiert. Jedes ExpandaEVE-Konstrukt wird vor der Ausführung auf ein CompactaEVE-Symbol heruntergebrochen. Diese Seite dokumentiert die kompakten Symbole, was der Compiler akzeptiert und wie ein kompiliertes Muster entscheidet, ob ein Kandidat trifft.
Du musst CompactaEVE nicht von Hand schreiben: der ExpandaEVE-Übersetzer erzeugt es. Aber das Lesen ist nützlich, um genau zu verstehen, wie sich ein Muster verhält, und ein Dokument kann direkt im kompakten Dialekt verfasst werden.
Die kompakten Anweisungsformen
Die dokumentweiten Direktiven behalten dieselben Namen in Kleinbuchstaben:
| ExpandaEVE | CompactaEVE |
|---|---|
DEFINE name AS id |
define name as id |
LET function(name) BE a OR b |
let &name be a|b |
REALM x |
realm x |
HEAR n AS body / FIND n AS body |
hear n as body |
MATCH n AS body |
match n as body |
ANYWHERE n AS ... |
anywhere n as g1 !! g2 |
SEQUENCE n AS ... |
sequence n as ... |
Klassenmitglieder und Gruppenarme werden durch den Balken | statt durch OR getrennt. Eine Klasse wird mit &name referenziert. Der Rest dieser Seite behandelt den Musterrumpf einer Fuzzy-Regel, wo die kompakten Symbole leben.
Wurzelmarker
Genau ein Wurzelmarker trennt den Wurzelstamm vom Rest des Musters:
| Symbol | Aus ExpandaEVE | Bedeutung |
|---|---|---|
[^^] |
(WHOLE) |
Die Wurzel trifft als ganzes Wort. Die Route muss bis zu einer Wortgrenze laufen. |
[*^] |
(ROOT) |
Die Wurzel ist ein Stamm, auf dem spätere Teile aufbauen. |
Der Text vor dem Marker ist der Wurzelstamm. ni[*^] hat den Stamm ni; spic[^^] hat den Stamm spic und erfordert einen ganzwortigen Treffer.
Parts: die Bestandteile eines Fragments
Ein Fragment (eine Wurzel, ein Gruppenarm, ein Suffix) wird in eine geordnete Liste von Parts geparst. Der Compiler erkennt diese Tokens; alles andere sammelt sich als literaler Lauf an.
| Token | Art | Trifft |
|---|---|---|
| einfacher Text | Literal | Die exakten Zeichen, der Reihe nach. |
@ |
Any | Genau ein Zeichen Wortmaterial. |
(#*) |
Gap | Ein Lauf beliebiger Zeichen, ob Buchstaben oder nicht. Nichtdeterministisch: er kann an jeder erreichbaren Position enden. |
($^) |
Gap (Buchstaben) | Ein Lauf nur aus Buchstaben (Wortmaterial). |
[swap:...] |
Swap | Einer von mehreren alternativen Armen mit Grenzregeln. |
Ein Literal wird exakt getroffen. @ verbraucht ein Wort-Byte. Ein Gap ist die Toleranz der Engine für eingefügte Zeichen: es kann null oder mehr Positionen überspringen, und der Matcher probiert jedes erreichbare Ende.
Wortmaterial
Wortmaterial ist ein ASCII-Buchstabe oder ein beliebiges Nicht-ASCII-Byte. Eine Mehrbyte-Glyphe wie ein Emoji ist ein Lauf von Wort-Bytes, Glyphenläufe tokenisieren und begrenzen also wie Wörter. Kein ASCII-Byte wird als Symbol-Byte behandelt, gewöhnlicher Text bleibt also unverändert.
Wurzeln und Wurzelalternativen
Die Wurzel kann drei Formen annehmen:
- Ein einfacher Stamm:
masturb[*^]kompiliert zu einer Wurzel. - Eine Klassenreferenz:
&name...expandiert so, dass jedes Klassenmitglied zu einer Wurzelalternative wird, wobei jeder nachfolgende Text erhalten bleibt. - Eine segmentierte Wurzel
[[..][..]]: siehe Segmentierte Wurzeln.
Führende Override-Klammern und Präfixprodukte erzeugen weitere Wurzelalternativen:
[text;]vor der Wurzel ersetzt das führende Literal der Wurzel durchtextund erzeugt eine alternative Schreibweise. Dies ist das, wozu ALIAS heruntergebrochen wird. Ein[text^^;]- oder[text*^;]-Override setzt auch die Grenze dieser Alternative.[+[a|b]]vor der Wurzel ist ein Präfix-Kreuzprodukt: jedes aufgeführte Präfix wird jeder Wurzel vorangestellt, was die Alternativen vervielfacht. Dies ist das, was ALSO verwendet, wenn es vor der Wurzel steht, und wozu eine Klassenreferenz innerhalb von[+[...]]expandiert.
Wurzelalternativen sind nach längstem Literal zuerst geordnet, sodass eine spezifischere Schreibweise vor einer kürzeren probiert wird. Eine Wurzelalternative wird frühzeitig übersprungen, wenn ein Literal, das sie verbrauchen muss, im Kandidaten fehlt.
Segmentierte Wurzeln
Eine segmentierte Wurzel wird [[seg1][seg2]...] geschrieben, wobei ein Segment, das auf * endet, ein Einstiegspunkt ist. Sie erzeugt Alternativen, die an jedem markierten Segment beginnen, optional durch die früheren Segmente präfixiert. Das lässt eine Wurzel wie re[tard] sowohl als ganzes Wort als auch vom flektierbaren Segment aus erreichen. Eine segmentierte Wurzel ohne markierten Einstiegspunkt ist ein Fehler.
Suffixe und Endungen (nachfolgend)
Endungen leben in der nachfolgenden Suffixliste. In CompactaEVE werden sie mit |[a|b|...] nach der Wurzel hinzugefügt, was das ist, wozu suffix(...) heruntergebrochen wird. Eine Route trifft nur, wenn der Kandidat auf einem der nachfolgenden Suffixe endet und bis zum Ende des Worts läuft.
Ein leerer Arm (NONE) macht das Suffix optional.
Umschreib-Suffixe
Ein nachfolgender Arm, der from>to geschrieben wird, ist ein Umschreiben. Er trifft einen Kandidaten, der auf to endet, indem er to abstreift, from anhängt und das Ergebnis gegen das Kernmuster testet. y>ies lässt eine Wurzel, die auf y endet, auch ein Wort treffen, das auf ies endet, sodass eine Wurzel sowohl baby als auch babies erreicht. Der >-Marker ist die einzige Stelle, an der ein Umschreiben interpretiert wird, sodass sich jeder Leser nachfolgender Suffixe über seine Bedeutung einig ist.
Gruppen
Zwischen der Wurzel und den nachfolgenden Suffixen ist das Muster eine Folge von Gruppen. Eine Gruppe ist ein Satz alternativer Arme, von denen einer sie erfüllen kann. Eine Gruppe hat eine Art:
| Art | CompactaEVE | Verhalten |
|---|---|---|
| Normal | `[a | b]` |
| Plus (schwebend) | `[+[a | b]]` |
| Hard (verankert) | eine harte Klassenreferenz | Eine verankerte Alternative, die vom Anfang aus getroffen wird. |
Ein Arm, der leer ist, macht seine Gruppe optional. Eine Gruppe, die als bloßes Gap geschrieben wird, (#*) oder ($^), ist eine optionale Gap-Gruppe, was das ist, wozu ein eigenständiges GAP oder LETTERS zwischen Teilen heruntergebrochen wird.
Klassenreferenzen als Gruppen
&name in der Gruppenposition expandiert die Klasse zu einer Gruppe von Armen, einem pro Mitglied. &!name macht die Gruppe optional (ein zusätzlicher leerer Arm wird hinzugefügt), was das ist, wozu MAYBE FUNCTION heruntergebrochen wird. Eine Referenz kann [^^] oder [*^] tragen, um hartes oder weiches Matching zu erzwingen; andernfalls erbt sie die deklarierte Härte der Klasse. Eine harte Klassenreferenz wird zu einer harten verankerten Gruppe.
Plus-Gruppen (schwebend)
Eine Plus-Gruppe [+[...]] sitzt nicht in fester Reihenfolge. Nachdem die Wurzel und die normalen Gruppen verbraucht sind, berechnet der Matcher jede erreichbare Position und lässt die Plus-Gruppe an jeder von ihnen andocken, bis zum Ende des Worts laufend. So schweben ADDITIVE-Funktionen und ALSO relativ zum Stamm.
Swaps
[swap:a|b] trifft einen beliebigen Arm an einer Position. Jeder Arm trägt Grenzflags, die durch seine Sternchen entschieden werden:
- Ein einzelnes führendes
*gibt die Startgrenze frei. - Ein einzelnes nachfolgendes
*gibt die Endgrenze frei. - Kein Sternchen oder ein doppelt führendes
**verankert beide Seiten.
Eine verankerte Seite erfordert dort eine Wortgrenze: der Anfang muss auf ein Nicht-Wort-Byte folgen (oder der Stringanfang sein), und das Ende muss einem Nicht-Wort-Byte vorausgehen (oder das Stringende sein). Ein Swap kann inline in einem Fragment oder als eigene Gruppe geschrieben werden.
Ausschlüsse (Veto)
[-[a|b]] ist eine Vetoliste, was das ist, wozu NEVER heruntergebrochen wird. Jeder aufgeführte Ausdruck ist ein einfacher Teilstring-Test gegen die ganze Zeile, kleingeschrieben. Wenn irgendein Ausdruck vorhanden ist, feuert das Muster nicht, unabhängig vom Rest des Treffers.
Precheck- und Post-Gating
Zwei Konstrukte gaten ein Muster anhand der umgebenden Zeile:
{pre:a|b}ist ein Precheck, aus BEFORE. Das Muster bleibt inaktiv, sofern nicht einer der Ausdrücke ein Teilstring der Zeile ist, kleingeschrieben.{post:a|b}ist eine Post-Bedingung, aus AFTER. Sie wird am Wurzelmarker als optionale führende Gruppe erlaubter Endungen eingefügt.
Ein gegatetes Muster (eines mit einem Precheck) feuert nur, wenn ein Precheck-Ausdruck in der Zeile vorhanden ist, oder wenn der Kandidat die Post-Bedingung selbst erfüllt: er beginnt mit dem Wurzelstamm und endet mit einer der Post-Endungen, wobei ein nachfolgendes Plural-s toleriert wird. Die Precheck- und Veto-Fakten hängen nur von der Zeile ab, nicht vom Kandidaten, sie werden also einmal pro Zeile berechnet und über Kandidaten hinweg wiederverwendet.
Skelette
{skel:...} ist die Skelett-Whitelist, aus SKELETON. Sie wird zur Kompilierzeit in einen Satz konkreter Wörter expandiert. Ein Kandidat, der genau einem dieser Wörter gleicht, trifft sofort, bevor der Kern-Matcher läuft.
Innerhalb eines Skeletts:
[a,b,c]ist eine Inline-Auswahlliste: eine Position, die jedes kommagetrennte Mitglied sein kann. Mitglieder können mehrere Zeichen umfassen. Whitespace um ein Mitglied wird entfernt.&nameexpandiert zu den Mitgliedern dieser Klasse. Ein numerischer Klassenname expandiert Ziffer für Ziffer; ein benannter Klassenname expandiert als Buchstaben.
Die Expansion ist das vollständige Kreuzprodukt jeder Auswahl, kleingeschrieben.
Flag-Wrapper
{name:y?...} und {name:n?...} wickeln ein Muster in eine Flag-Bedingung, aus FLAG. Die y-Form erfordert das Flag an, die n-Form erfordert es aus. Mehrere Wrapper können verschachtelt werden. Der Flag-Name muss mit define deklariert sein, sonst schlägt das Laden des Dokuments fehl. Die deklarierten Flags sind das, was der Filter als Kategorie meldet.
Kommentare
{#c:...} ist ein Inline-Kommentar, aus NOTE. Er wird vor der Kompilierung entfernt, einschließlich verschachtelter Klammern. Ganzzeilige Kommentare verwenden ein führendes #.
Wie ein Fuzzy-Muster trifft
Wenn ein Kandidatenwort gegen ein kompiliertes Fuzzy-Muster getestet wird, führt die Engine diese Prüfungen der Reihe nach aus:
- Gating. Wenn das Muster einen Precheck hat und weder ein Precheck-Ausdruck in der Zeile vorhanden ist noch die Post-Bedingung erfüllt ist, trifft es nicht. Wenn irgendein Veto-Ausdruck in der Zeile vorhanden ist, trifft es nicht.
- Skelett. Wenn der Kandidat genau einem Skelettwort gleicht, trifft er.
- Kerntreffer. Die Haupt-Engine läuft (unten).
- Umschreib-Fallback. Für jedes Umschreib-Suffix wird, wenn der Kandidat auf der
to-Seite endet, diefrom-Seite wiederhergestellt und der Kerntreffer am wiederhergestellten Wort erneut versucht.
Der Kerntreffer
Der Kern-Matcher entscheidet, ob der ganze Kandidat durch eine Route abgedeckt ist:
- Ein schnelles Reject überspringt den Kandidaten, wenn ihm jedes Literal fehlt, das eine Kernroute enthalten muss.
- Harte verankerte Gruppen werden vom Anfang aus probiert; eine Route, die eine erlaubte Endung erreicht, trifft.
- Jede Wurzelalternative wird vom Anfang aus ausgeführt. Eine Wurzel, deren erforderliche Literale fehlen, wird übersprungen. Die erreichbaren Enden speisen die Folge normaler Gruppen.
- Die normalen Gruppen werden der Reihe nach von den Wurzelenden aus durchgefädelt. Eine Route trifft, wenn sie ein erlaubtes nachfolgendes Suffix erreicht, das bis zum Ende des Worts läuft. Sofern die Route nicht rein literal ist, muss mindestens ein nicht leerer Arm gefeuert haben.
- Schwebende Plus-Gruppen werden an jedem erreichbaren Slot probiert, und eine Plus-Gruppe trifft, wenn einer ihrer Arme von einem erreichbaren Anker bis zum Ende des Worts läuft.
Wortgrenzen ergeben sich aus Wortmaterial: eine Grenze existiert an den Stringenden und überall dort, wo ein Nicht-Wort-Byte auf ein Wort-Byte trifft. Gaps überspringen Läufe von Zeichen nichtdeterministisch, sodass der Matcher jede Position erkundet, die ein Gap erreichen kann.
Anker und der Scan-Prefilter
Für jede Fuzzy-Regel berechnet der Compiler einen Satz erforderlicher literaler Anker: Literale derart, dass ein Kandidat, der keines von ihnen enthält, nicht treffen kann. Wenn eine Regel ohne ein garantiertes Literal treffen kann (zum Beispiel eine rein aus Gaps bestehende oder gegatete Route), ist ihr Ankersatz leer und die Regel wird immer ausgeführt. Die Anker jeder Regel bauen einen Aho-Corasick-Prefilter, der in einem Durchgang über eine Nachricht markiert, welche Regeln möglicherweise treffen könnten, sodass Regeln, deren Literale fehlen, übersprungen werden. Dies ist nur eine Optimierung: sie überspringt niemals eine Regel, die treffen könnte.
Strikte Regeln (MATCH)
Eine MATCH-Regel verwendet die strikte Sprache statt der Fuzzy-Engine. Ein striktes Muster ist verankert: es gelingt nur, wenn seine Terme die gesamte Eingabe von Anfang bis Ende verbrauchen. Es wird für strukturierte Eingaben wie Zahlen und Adressen verwendet, und es kann benannte Stücke erfassen.
Strikte Primitive
| Schlüsselwort | Trifft |
|---|---|
digit |
Genau eine Ziffer. |
digits |
Ein Lauf von Ziffern. |
letter |
Genau einen Buchstaben. |
letters |
Ein Lauf von Buchstaben. |
word |
Ein Lauf von Buchstaben, Ziffern oder Unterstrichen. |
number |
Ein Lauf von Ziffern. |
ip |
Ein Lauf von Ziffern und Punkten. |
space |
Genau ein Whitespace-Zeichen. |
spaces |
Ein Lauf von Whitespace. |
anything |
Ein beliebiger Textabschnitt. |
Das Schlüsselwort-Matching ignoriert Groß- und Kleinschreibung. Ein "..."-Token ist ein Literal, wobei Backslash-Escapes beachtet werden.
Strikte Quantoren und Struktur
| Konstrukt | Wirkung |
|---|---|
any x |
Null oder mehr von x, gierig. |
many x |
Ein oder mehr von x, gierig. |
maybe x |
Null oder eins von x. |
m to n x |
Zwischen m und n von x. |
n digit (usw.) |
Genau n von einer Klasse, zum Beispiel 3 digit. |
( ... ) |
Eine als Teilfolge getroffene Gruppe. |
x or y |
Alternation: einer der Zweige kann die Position erfüllen. |
then |
Optionaler lesbarer Klebstoff zwischen Termen; ignoriert. |
x as name |
Erfasst den getroffenen Text von x unter name. |
Ein auf eine Plural-Klasse angewendeter Quantor verengt sie auf ihre Einzelzeichen-Form, sodass sie sich zeichenweise wiederholt. Wiederholung ist nur gierig; es gibt keinen faulen Modus, und eine leere Wiederholung kann nicht schleifen.
Listenreferenzen und Fuzzy-Find in strikt
&name in einem strikten Muster expandiert zu einer Alternation der Klassenmitglieder als Literale. Ein Backtick-Term find `pattern` bettet ein Fuzzy-EVE-Muster ein: der strikte Matcher übergibt eine Nicht-Leerzeichen-Spanne an das kompilierte Fuzzy-Muster und akzeptiert die Spanne, wenn sie trifft. Beide benötigen die Registry, die verfügbar ist, wenn ein Dokument kompiliert wird.
Anywhere- und Sequence-Regeln
ANYWHERE und SEQUENCE sind separate Regelarten. ANYWHERE feuert, wenn jede Gruppe (getrennt durch !! in der kompakten Form, WITH in ExpandaEVE) ein Mitglied hat, das irgendwo in der Nachricht gefunden wird; jedes Mitglied wird als ganzwortiger Fuzzy-Matcher kompiliert, und die Regel braucht mindestens zwei Gruppen. SEQUENCE trifft einen geordneten Lauf von Glyphen und wird vom Symbol-Board verwendet, das separat dokumentiert ist; ein mirror-Präfix akzeptiert auch die umgekehrte Reihenfolge, und die Regel braucht mindestens zwei Glyphen.