Vorwort
Vor kurzem stellte ich fest, dass die Leistung von Regelmäßigkeiten in JavaScript an einigen Stellen etwas von denen in anderen Sprachen oder Tools unterscheidet und relativ alternativ ist. Obwohl es für Sie fast unmöglich ist, sie zu schreiben, und Sie die unten erwähnten Regeln kaum verwenden können, ist es doch gut, sie zu verstehen.
Die Code -Beispiele in diesem Artikel werden in einer JavaScript -Umgebung ausgeführt, die mit ES5 kompatibel ist. Das heißt, die Leistung in Versionen vor IE9, Versionen um FX4 usw. ist wahrscheinlich anders als das, was ich unten erwähnt habe.
1. leere Charakterklasse
Eine Zeichenklasse, die keine [] enthält, wird als leere empty char class bezeichnet. Ich glaube, Sie haben nie gehört, dass andere es nennen, weil diese Schreibmethode in anderen Sprachen illegal ist und alle Dokumente und Tutorials nicht über eine illegale Syntax sprechen. Lassen Sie mich nachweisen, wie andere Sprachen oder Tools diesen Fehler melden:
$ echo | grep '[]' grep: unerreicht [oder [^$ echo | SED '/[]/' SED: -e Ausdruck Nr. 1, Zeichen 4: Unterminierte Adresse regulärer Ausdruck $ echo | awk '/[]/' awk: cmd. Zeile: 1: /[] /awk: cmd. Zeile: 1: ^ Unterminierte Regexpawk: CMD. Zeile: 1: Fehler: unerreicht [oder [^:/[] // $ echo | perl -ne '/[]/' unerreicht [in Regex; Markiert von <-hier in m/ [<-hier]/ bei -e Zeile 1. $ echo | Ruby -ne '/[]/' -E: 1: leere Zeichenklasse:/[]/$ python -c 'import re.match ("[]", "")' TracBack (letztes Anruf letztes): Datei "<string>", Zeile 1, in <module> Datei "e: /python/lib/re.py). "E: /python/lib/re.py", Zeile 244, in _compile erhöhen Fehler, V # Invalid Expressionsre_Constants.Error: Unerwartetes Ende des regulären Ausdrucks In JavaScript ist die leere Zeichenklasse eine legale reguläre Komponente, aber ihre Wirkung ist "nie übereinstimmt", dh alles wird scheitern. Es entspricht der Wirkung eines (empty negative lookahead)(?!) :
js> "was auch immer/n" .Match (/[]/g) // Null -Zeichenklasse, niemals mit nulljs> "was auch immer/n" .Match (/(?!)/G) // null negativ vorwärts und schau um und passt niemals mit Null überein.
Offensichtlich ist so etwas in JavaScript nutzlos.
2. Negieren Sie die leere Zeichenklasse
Negative Charakterklassen, die keine Zeichen enthalten, werden auch als negative leere Zeichenklasse oder leere negative Zeichenklasse bezeichnet, da dieses Substantiv "selbst geschaffen" und der oben genannten leeren Zeichenklasse ähnlich war. Diese Schreibmethode ist auch in anderen Sprachen illegal:
$ echo | grep '[^]' grep: unerreicht [oder [^$ echo | sed '/[^]/' sed: -e Ausdruck Nr. 1, Zeichen 5: Unterminierte Adresse regulärer Ausdruck $ echo | awk '/[^]/' awk: cmd. Zeile: 1: /[^] /awk: cmd. Zeile: 1: ^ Unterminierte Regexpawk: CMD. Zeile: 1: Fehler: unerreicht [oder [^:/[^] // $ echo | perl -ne '/[^]/' unerreicht [in Regex; Markiert von <-hier in m/ [<-hier ^]/ at -e Zeile 1. $ echo | Ruby -ne '/[^]/' -E: 1: leere Zeichenklasse:/[^]/$ python -c 'import re.match ("[^]", "")' TraceBack (letztes Anruf letztes): Datei "<string>", Zeile 1, in <modul> Datei "e:/Python/lib/re.py, line Flags) .Match (String) -Datei "e: /python/lib/re.py", Zeile 244, in _compile erhöhen Erst In JavaScript ist die Negation der Null -Charakterklasse eine legale reguläre Komponente. Sein Effekt ist genau das Gegenteil der Auswirkung der Null -Charakterklasse. Es kann mit jedem Charakter übereinstimmen, einschließlich der neuen Linie "/n" , dh es entspricht dem gemeinsamen [/s/S] und [/w/W] :
JS> "Was auch immer/n" .Match (/[^]/g) // Neizontal -Charakter -Klasse, passen Sie zu jedem Charakter ["W", "H", "A", "T", "E", "V", "E", "R", ","/n "] JS>" WEITER/n ".Match (/s]/s. "T", "E", "V", "E", "R", ","/n "]
Es ist zu beachten, dass es nicht als "permanente Matching -Regelmäßigkeit" bezeichnet werden kann, da die Charakterklasse über einen Charakter verfügt, der übereinstimmt. Wenn die Zielzeichenfolge leer ist oder von der linken Regelmäßigkeit konsumiert wurde, fällt das Spiel beispielsweise aus:
js> /abc -·^/.test("abc ") // Es gibt keine Zeichen nach C, und die Matching fehlgeschlagen.FalseWenn Sie die wahren "dauerhaften Übereinstimmungsregeln" kennen möchten, können Sie einen Artikel, den ich zuvor übersetzt habe
3. []] und [^]]
Dies ist relativ einfach, das heißt: In den regulären Ausdrücken von Perl und einigen anderen Linux -Befehlen, wenn die Charakterklasse [] unmittelbar nach []] linken quadratischen Klammer eine rechte quadratische Klammer enthält, wird die rechte quadratische Klammer als normaler Charakter angesehen, dh nur übereinstimmen "]". In JavaScript wird diese Regelmäßigkeit als leere Charakterklasse anerkannt, gefolgt von einer rechten Quadratklammer, und die leere Zeichenklasse wird nichts übereinstimmen .[^]] ist ähnlich: In JavaScript entspricht es einem willkürlichen Charakter (negative Null-Charakter-Klasse), gefolgt von einer rechten quadratischen Klammer wie "a]","b]" , während es in anderen Sprachen zu allen Nicht-]-Zeichen passt.
$ perl -e 'print "]" = ~/[]]/' 1 $ js -e 'drucken (/[]]/. test ("]")' falsch $ perl -e 'drucken "x" = ~/[^]]/' 1 $ js -e 'drucken (/[^]/. test ("x")') 'Falsches Falsch4. $ Anchor Point
Einige Anfänger glauben, dass $ dem neuen Charakter "/n" übereinstimmt, was ein großer Fehler ist. $ ist eine Behauptung mit Null-Breiten, es ist unmöglich, einem echten Charakter übereinzustimmen, es kann nur mit einer Position übereinstimmen. Der Unterschied, über den ich sprechen möchte, erfolgt im nicht-multi-line-Modus: Sie könnten denken, dass $ im nicht-multi-line-Modus nicht mit der Position nach dem letzten Charakter übereinstimmt? Eigentlich ist es nicht so einfach. Wenn in den meisten anderen Sprachen das letzte Zeichen in der Zielzeichenfolge das Newline -Zeichen "/n" ist, passt $ auch mit der Position vor der Newline überein, dh den beiden Positionen auf der linken und rechten Seite der Linienpause am Ende. Viele Sprachen haben zwei Notationen /z und /z. Wenn Sie den Unterschied zwischen ihnen kennen, sollten Sie verstehen, dass in anderen Sprachen (Perl, Python, PHP, Java, C#...) $ im Nicht-Multi-Line-Modus /z äquivalent ist, während in JavaScript $ im Nicht-Multi-Line-Modus äquivalent zu /z übereinstimmt (es wird nur mit der letzten Position übereinstimmen, unabhängig davon, ob der letzte Charakter eine neue Line ist). Ruby ist ein spezieller Fall, da es standardmäßig mit dem Multi-Line-Modus ausfällt. $ im Multi-Line-Modus entspricht der Position vor jeder Newline und umfasst natürlich auch die Leitungsunterbrechung, die am Ende möglicherweise angezeigt wird. Yu Shengs Buch "reguläre Richtlinien" spricht auch über diese Punkte.
$ perl -e 'druck "was auch immer/n" = ~ s/$/Ersetzen Zeichen/RG
5. Dot Metacharacter "."
In regulären Ausdrücken in JavaScript, der Dot Metacharacter "." Kann alle Zeichen mit Ausnahme von vier Zeilen-Terminatoren ( /R-Carriage-Rückgabe, /N-Line Newline, /U2028-Line-Separator, /U2029-Absatz-Separator) übereinstimmen, während in anderen gemeinsamen Sprachen nur Line Newline /N ausgeschlossen wird.
6. Vorwärts zitieren
Wir alle wissen, dass es in einem Stammgast eine Backreferenz gibt, dh einen Backslash + -Zahlen -Verweis auf die Zeichenfolge, die in der vorherigen Capture -Gruppe übereinstimmt. Der Zweck besteht darin, wieder übereinstimmen oder als Ersatzergebnis (/ wird $). Aber es gibt einen Sonderfall, dass die hintere Referenz die hintere Referenz verwendet, wenn die referenzierte Capture -Gruppe nicht begonnen hat (die linke Halterung ist begrenzt), was passiert, was passieren wird? Beispielsweise ist regulär /(/2(a)){2}/ (a) die zweite Erfassungsgruppe, aber das passende Ergebnis davon wird auf der linken Seite verwendet. Wir wissen, dass regelmäßige Übereinstimmungen von links nach rechts. Dies ist der Ursprung des Titels Forwards Referenz in diesem Abschnitt. Es ist kein strenger Konzept. Jetzt denken Sie darüber nach: Was wird der folgende JavaScript -Code zurückgeben:
JS>/(/2 (a)) {2}/. exec ("aaa") ???Bevor Sie diese Frage beantworten, werfen wir einen Blick auf die Leistung in anderen Sprachen. In ähnlicher Weise ist das Schreiben in anderen Sprachen im Grunde genommen ungültig:
$ echo aaa | grep '(/2 (a)) {2}' grep: Ungültige Rückreferenz $ echo aaa | sed -r '/(/2 (a)) {2}/' sed: -e Ausdruck Nr. 1, Zeichen 12: Illegale Rückreferenz $ echo aaa | awk '/(/2 (a)) {2}/' $ echo aaa | perl -ne 'print/(/2 (a)) {2}/' $ echo aaa | Ruby -ne 'drucken $ _ = ~/(/2 (a)) {2}/' $ python -c 'import re; drucken re.match ("(/2 (a)) {2}", "aaa")' keineEs gibt keinen Fehler in awk, da awk diese Rückreferenz nicht unterstützt und /2 als Zeichen mit ASCII -Code 2 interpretiert wird. Es gibt jedoch keinen Fehler in Perl Ruby Python. Ich weiß nicht, warum dieses Design von Perl gelernt werden sollte, aber die Auswirkungen sind gleich. In diesem Fall ist es unmöglich, erfolgreich abzustimmen.
In JavaScript meldet es nicht nur keinen Fehler, sondern kann auch erfolgreich mit ihm übereinstimmen. Mal sehen, dass die Antwort die gleiche ist wie die, die Sie gerade gedacht haben:
js> /(/2(a)) {2}/.exec("aaa")..aaa "," a "," a "] Um zu verhindern, dass Sie vergessen, was das Ergebnis von exec -Methode zurückgegeben wird, lassen Sie mich sagen. Das erste Element ist die vollständige passende Zeichenfolge, dh RegExp["$&"] , gefolgt von dem Inhalt jeder Capture -Gruppenübereinstimmung, dh RegExp.$1 und RegExp.$2. Warum kann das Matching erfolgreich sein? Was ist der Matching -Prozess? Mein Verständnis ist:
Zunächst geben wir die erste Capture-Gruppe (die links linke Klammer) ein, in der das erste gültige Match /2 ist, aber zu diesem Zeitpunkt war die zweite Capture-Gruppe (a) noch nicht in der Runde, so dass der Wert von RegExp.$2 noch undefined ist. Der Punkt ist, dass das Match erfolgreich ist. Fahren Sie weiter bis zur GO, und die zweite Capture -Gruppe (a) entspricht dem ersten A in der Zielzeichenfolge, und der Wert von RegExp.$2 wird auch "a" zugeordnet, und dann endet die erste Erfassungsgruppe (die ganz rechts rechts rechts rechts rechts rechts), der Wert von RegExp.$1 ist auch "a". Dann gibt es den Quantifizierer {2}, dh nach der ersten A in der Zielzeichenfolge wird eine neue Runde des Stimmens von regulärem (/2(a)) gestartet. Der Schlüsselpunkt ist hier: Der Wert von RegExp.$2 ist, dass der Wert von /2 übereinstimmt oder der Wert, der am Ende der ersten Runde des Matching "a" zugewiesen wird. Die Antwort lautet: "Nein", die Werte RegExp.$1 und RegExp.$2 werden als undefined gelöscht, und /1 und /2 entspricht dem ersten Mal, was ein leeres Zeichen erfolgreich abgibt (entspricht keinem Effekt, ob geschrieben oder nicht). Der zweite A in der Zielzeichenfolge wird erfolgreich übereinstimmt, und die Werte von RegExp.$1 und RegExp.$2 werden "wieder" ein "Wiederum der Wert von RegExp["$&"] wird zur vollständigen passenden Zeichenfolge, die ersten beiden a:" aa ".
In früheren Versionen von Firefox (3.6) wird der Neuanfang der Quantifizierer den Wert der vorhandenen erfassten Gruppe nicht beseitigen. In der zweiten Runde der Spiele wird /2 mit der zweiten A übereinstimmen, also:
js> /(/2(a)) {2}/.exec("aaa");..aaaa "," a "]Darüber hinaus hängt das Ende einer Erfassungsgruppe davon ab, ob die Schlussklasse geschlossen ist. Zum Beispiel/(a/1) {3}/. Obwohl die erste Capture -Gruppe angefangen hat, wenn /1 verwendet wird, ist sie noch nicht beendet. Dies ist auch eine Vorwärtsreferenz, daher ist die Übereinstimmung zwischen /1 noch leer:
js> /(a/1) <a <
Ein weiteres Beispiel:
js> /(?:(f)(o)(o)|(a(a)(r))*/.exec("foobar")...foobar ", undefiniert, undefiniert, undefiniert," B "," a "," R "] * ist ein Quantifizierer. Nach der ersten Matching -Runde: $ 1 IS "F", 2 $ ist "o", 3 US -Dollar "O", 4 US -Dollar sind undefiniert, 5 US -Dollar undefined und 6 US -Dollar undefined .
Zu Beginn der zweiten Spielrunde: Alle erfassten Werte werden auf undefined zurückgesetzt.
Nach der zweiten Spielrunde: $ 1 ist undefined , 2 US -Dollar undefined , 3 US -Dollar undefined , 4 US -Dollar "B", 5 US -Dollar "A" und 6 US -Dollar "R".
& wird als "Foobar" zugewiesen und das Match endet.
Zusammenfassen
Das obige ist der gesamte Inhalt, der die Unterschiede zwischen der Regelmäßigkeit von JavaScript und anderen Sprachen zusammenfasst. Ich hoffe, dass der Inhalt dieses Artikels für das Studium und die Arbeit aller hilfreich ist.