2015-06-17 3 views
12
<table((?!</table>).)*</table> 

alle Tags meine Tabelle übereinstimmt, jedochAusgeglichenes Greedy Token - Was den Punkt über die Platzierung vor der negative Vorschau unterscheidet

<table(.(?!</table>))*</table> 

nicht. Der zweite scheint Sinn zu ergeben, wenn ich versuche, den Ausdruck in Worte zu schreiben, aber ich kann den ersten nicht verstehen.

Kann mir jemand den Unterschied erklären?

Als Referenz habe ich den Begriff `Ausgeglichenes Greedy Token‘ von hier: http://www.rexegg.com/regex-quantifiers.html#tempered_greed

+0

Nebenbei bemerkt, dass diese "temperierte" Art besonders ineffizient ist. –

+0

@sln Nein, ich habe es nicht erfunden. Tatsächlich verweist der letzte Satz meiner Post, wo der Begriff herkam ... – jrahhali

+1

Dann .. _he_ hat es erfunden. In der Tat, das ist kein Standard-Jargon in Regex Land. Und wenn ich eine Umfrage machen würde, wette ich, dass 99% der Regex-Gurus darüber lachen würden. – sln

Antwort

30

Da Google diese Frage SO oben auf die Ergebnisse für die tempered greedy token zurück, fühle ich mich verpflichtet, eine umfassende Antwort zu geben.

Was ist ein ausgehärtetes Greedy Token?

Die rexegg.com tempered greedy token Referenz ist recht prägnant:

In (?:(?!{END}).)*, die * quantifier auf einen Punkt trifft, aber es ist jetzt ein temperiert Punkt. Der negative Lookahead (?!{END}) behauptet, dass das, was der aktuellen Position folgt, nicht die Zeichenfolge {END} ist. Daher kann der Punkt niemals mit der öffnenden Klammer von {END} übereinstimmen, was garantiert, dass wir nicht über den {END} Begrenzer springen werden.

, dass es: a temperierte gierig Token ist eine Art einer negierte Zeichenklasse für ein Zeichen Sequenz (vgl negated character class für ein einzelnes Zeichen).

HINWEIS: Der Unterschied zwischen einem temperierten gierigen Token und einer negierte Zeichenklasse ist, dass erstere nicht wirklich den Text übereinstimmt anders als die Sequenz selbst, sondern ein einzelne Zeichen, die nicht startet diese Sequenz . I.e.(?:(?!abc|xyz).)+ nicht def in defabc, passen aber defundbc, überein, da a die verbotene abc Sequenz beginnt, und bc nicht.

Es besteht aus:

  • (?:...)* - eine quantifizierte Nicht-Erfassung Gruppe (es eine Erfassungsgruppe sein kann, aber es macht keinen Sinn, jeden einzelnen Charakter zu erfassen) (a * kann + sein, es hängt ob ein leerer String Spiel erwartet wird)
  • (?!...) - eine negative lookahead, die tatsächlich eine Beschränkung des Wertes rechts von der aktuellen Position
  • . erlegt - (oder einem (in der Regel einzeln) Zeichen) ein verzehr Muster.

können wir jedoch immer weiter das Token Temperament von Abwechslungen im negativen Look-Ahead (zB (?!{(?:END|START|MID)})) oder durch Ersetzen der alle Anpassungs Punkt mit einem negierten Zeichenklasse (zB (?:(?!START|END|MID)[^<>]) wenn sie versuchen, Text innerhalb von Tags nur passend).

aufwendigste Teil Platzierung

Hinweis gibt es keine Erwähnung eine Konstruktion ist, wo ein verzehrender Teil (der Punkt in den ursprünglichen temperiert gierigen Token) vor der Look-Ahead platziert wird. Avinashs Antwort erklärt diesen Teil klar: (.(?!</table>))* passt zuerst auf ein beliebiges Zeichen (aber eine Zeilenschaltung ohne einen Modifikator DOTALL) und prüft dann, ob es nicht mit </table> übereinstimmt, was dazu führt, dass e in <table>table</table> nicht übereinstimmt. Der verbrauchende Teil (.) MUSS nach dem Temperieren Lookahead platziert werden.

Wann temperierte gierige Token zu verwenden?

Rexegg.com gibt eine Idee:

  • Wenn wir einen Textblock zwischen Trennzeichen 1 und 2 Trennzeichen ohne Substring 3 in-between (zB {START}(?:(?!{(?:MID|RESTART)}).)*?{END}
  • übereinstimmen soll Wenn wir vergleichen wollen ein Text ein bestimmtes Muster innerhalb ohne überzulaufen nachfolgende Blöcke enthält (zB statt faul Punktanpassung, wie in <table>.*?chair.*?</table>, würden wir so etwas wie <table>(?:(?!chair|</?table>).)*chair(?:(?!<table>).)*</table> verwenden).
  • Wenn wir die kürzesten Fenster möglich zwischen 2 str übereinstimmen sollen iings. Lazy Matching wird nicht helfen, wenn Sie abc 2 xyz von abc 1 abc 2 xyz erhalten müssen (siehe abc.*?xyz und abc(?:(?!abc).)*?xyz).

Leistungsproblem

Ausgeglichenes gierig Token ist ressourcenaufwändig als Look-Ahead-Check nach jedem Zeichen mit dem raubend Muster abgestimmt durchgeführt wird. Unrolling the loop technique kann die temperierte Greedy-Token-Leistung erheblich steigern.

Sag mal, wollen wirabc 2 xyz in abc 1 abc 2 xyz 3 xyz entsprechen.Statt jedes Zeichen zwischen abc und xyz mit abc(?:(?!abc|xyz).)*xyz zu prüfen, können wir alle Zeichen überspringen, die nicht a oder x mit [^ax]* sind, und dann alle a übereinstimmen, die nicht mit bc (mit a(?!bc)) und alle x gefolgt werden, die nicht mit yz befolgt werden (mit x(?!yz)): abc[^ax]*(?:a(?!bc)[^ax]*|x(?!yz)[^ax]*)*xyz.

+2

Nachdem dieser Beitrag im Kommentarbereich veröffentlicht wurde, habe ich mich entschieden, stattdessen Ihre sehr ausführliche Antwort zu akzeptieren. Danke, dass Sie sich die Zeit genommen haben, dies zusammen zu stellen. – jrahhali

9

((?!</table>).)* würde Schecks für diesen bestimmten Charakter gelegt werden, gehen darf kein Startzeichen in der Zeichenfolge </table> sein. Wenn ja, dann stimmt nur dieses bestimmte Zeichen überein. * wiederholt die gleiche Null oder mehrmals.

(.(?!</table>))* passt nur dann auf ein beliebiges Zeichen, wenn nicht </table>, null oder mehrere Male gefolgt wird. Dies würde also alle Zeichen innerhalb des Tabellen-Tags übereinstimmen, außer dem letzten Zeichen, da dem letzten Zeichen gefolgt wird von </table>. Und das folgende Muster </table> behauptet, dass am Ende des Matches ein schließendes Tabellentag vorhanden sein muss. Dies führt dazu, dass die Übereinstimmung fehlschlägt.

Siehe here

+0

Ich kämpfe immer noch mit dem ersten Absatz zu verstehen. Gute Nachricht ist, dass ich Ihre Erklärung darüber verstehe, warum (. (?)) * fehlschlägt. EDIT: Ohhh, ok, ich denke ich verstehe jetzt! – jrahhali

3

A gierig temperiert Token wirklich bedeutet nur:

"Spiel, aber nur bis zu einem Punkt"

wie Sie es tun:

Sie das setzen Token Sie möchten nicht als negative Lookahead (?!notAllowedToMatch) i n vor einem Punkt . (passen irgendeine Sache), dann wiederholen Sie das Ganze mit einem Sternchen *:

((?!notAllowedToMatch).)*

, wie es funktioniert:

" schau, und esse einen " immer und immer wieder und verschiebe ein Zeichen zur Zeit von links nach rechts durch die Eingabezeichenfolge, bis die d Es wird eine zugelassene Sequenz (oder das Ende einer Zeichenfolge) angezeigt, an der die Übereinstimmung endet.

Wiktors ausführlichere Antwort ist nett, ich dachte nur eine einfachere Erklärung war in Ordnung.

Verwandte Themen