Dieses Mal zeige ich Ihnen, wie Sie das Backtracking mit regulären Ausdrücken in js richtig verstehen, welche Vorsichtsmaßnahmen es gibt, um das Backtracking mit regulären Ausdrücken in js korrekt zu verwenden, und im Folgenden finden Sie praktische Fälle , lass uns einen Blick darauf werfen. Bei der Implementierung regulärer Ausdrücke ist Backtracking eine grundlegende Komponente des Matching-Prozesses und der Grund, warum reguläre Ausdrücke so nützlich und leistungsstark sind. Allerdings ist das Zurückverfolgen rechenintensiv und kann bei fehlerhaftem Design zum Kontrollverlust führen. Backtracking ist der einzige Faktor, der sich auf die Gesamtleistung auswirkt. Der Schlüssel zum Schreiben effizienter regulärer Ausdrücke kann sein, zu verstehen, wie es funktioniert und wie man die Häufigkeit seiner Verwendung reduziert.
Wenn ein regulärer Ausdruck die Zielzeichenfolge scannt, von Scan Die Komponenten des regulären Ausdrucks werden nacheinander von links nach rechts durchsucht und geprüft, ob an jeder Position eine Übereinstimmung gefunden werden kann. Für jeden Quantor und Zweig muss festgelegt werden, wie vorzugehen ist. Wenn es sich um einen Quantifizierer handelt (z. B. *, +? oder {2,}), muss der reguläre Ausdruck bestimmen, wann versucht werden soll, weitere Zeichen abzugleichen (über den Operator |). Beginnen Sie mit diesen Wählen Sie eine der Optionen zum Ausprobieren.
Wenn die Regex eine solche Entscheidung trifft, merkt sie sich bei Bedarf eine andere Option zur späteren Verwendung. Wenn das ausgewählte Schema erfolgreich übereinstimmt, scannt der reguläre Ausdruck weiterhin die Vorlage für reguläre Ausdrücke. Wenn auch die restlichen Übereinstimmungen erfolgreich sind, wird der Abgleich beendet. Wenn die gewählte Option jedoch keine Übereinstimmung findet oder wenn nachfolgende Übereinstimmungen fehlschlagen, kehrt die Regex zum letzten Entscheidungspunkt zurück und wählt eine der verbleibenden Optionen aus. Setzen Sie diesen Vorgang fort, bis eine Übereinstimmung gefunden wird oder alle möglichen Permutationen von Quantoren und Verzweigungsoptionen ausprobiert wurden. Anschließend wird der Vorgang abgebrochen, dann zum nächsten Zeichen am Anfang des Vorgangs übergegangen und der Vorgang wiederholt.
Der folgende Code zeigt beispielsweise, wie dieser Prozess Verzweigungen durch Backtracking verarbeitet.
Die obige Zeile des regulären Ausdrucks wird verwendet, um „/h(ello|appy) hippo/.test("hello there, happy hippo");
“ abzugleichen. Zu Beginn des Tests suchten wir nach einem h. Der erste Buchstabe der Zielzeichenfolge war zufällig h, und wir fanden ihn sofort. Als nächstes bietet der Unterausdruck (ello|appy) zwei Verarbeitungsoptionen. Der reguläre Ausdruck wählt die Option ganz links aus (die Zweigauswahl erfolgt immer von links nach rechts), prüft, ob ello mit dem nächsten Zeichen der Zeichenfolge übereinstimmt, und dann stimmt der reguläre Ausdruck mit den folgenden Leerzeichen überein. hello hippo
happy hippo
Allerdings gerät der reguläre Ausdruck bei der nächsten Übereinstimmung „in eine Sackgasse“, da das h in hippo nicht mit dem nächsten Buchstaben t in der Zeichenfolge übereinstimmen kann. Der reguläre Ausdruck kann an dieser Stelle nicht aufgeben, da er noch nicht alle Optionen ausprobiert hat. Daher kehrt er zum letzten Prüfpunkt zurück (nachdem er mit dem anfänglichen h übereinstimmt) und versucht, die zweite Verzweigungsoption zu finden. Da der Abgleich jedoch nicht erfolgreich war und es keine weiteren Optionen gab, ging der reguläre Ausdruck davon aus, dass der Abgleich ab dem ersten Zeichen der Zeichenfolge nicht erfolgreich sein würde, und begann die Suche erneut ab dem zweiten Zeichen. Der reguläre Ausdruck konnte kein h finden, also suchte er weiter rückwärts, bis er den 14. Buchstaben fand, der mit dem glücklichen h übereinstimmte. Dann verzweigt der reguläre Ausdruck erneut, und dieses Mal findet ello keine Übereinstimmung, aber im zweiten Zweig nach dem Zurückverfolgen findet er eine Übereinstimmung mit der gesamten Zeichenfolge „happy hippo“, und die Übereinstimmung ist erfolgreich.
Als weiteres Beispiel demonstriert der folgende Code das Backtracking mit wiederholten Quantifizierern.
Der reguläre Ausdruck entspricht zuerst den drei Buchstabenam Anfang der Zeichenfolge und dann .*. Der Punkt bedeutet, dass alle Zeichen außer Zeilenumbrüchen übereinstimmen, und das Sternchen, ein „gieriger“ Quantifizierer, bedeutet, dass es null oder mehrere Male wiederholt wird, um so viele Übereinstimmungen wie möglich zu erzielen. Da die Zielzeichenfolge keine Zeilenumbrüche enthält, stimmt der reguläre Ausdruck mit der gesamten verbleibenden Zeichenfolge überein! Da jedoch in der Regex-Vorlage mehr Inhalte vorhanden sind, die übereinstimmen, versucht die Regex, mit < übereinzustimmen. Da der Abgleich am Ende der Zeichenfolge fehlschlägt, gehen wir jeweils ein Zeichen zurück und versuchen, einen Abgleich mit < durchzuführen, bis der reguläre Ausdruck an die Position
zurückkehrt. Als nächstes wird versucht, eine Übereinstimmung mit / zu finden (wobei der Backslash maskiert wird), was erfolgreich zutrifft, und dann mit p, was nicht der Fall ist. Der reguläre Ausdruck geht weiter zurück und wiederholt diesen Vorgang, bis er schließlich mit übereinstimmt. Um eine erfolgreiche Übereinstimmung zurückzugeben, muss vom Kopf des ersten Absatzes bis zum Ende des letzten Absatzes gescannt werden, was möglicherweise nicht das gewünschte Ergebnis ist.var str = "<p>Para 1.</p>" +"<img src='smiley.jpg'>" +"<p>Para 2.</p>" +"<p>p.</p>"; /<p>.*<\/p>/i.test(str);
Den Quantifizierer „gierig“ * im regulären Ausdruck in den Quantifizierer „faul“ (auch bekannt als „nicht gierig“) * ändern, um eine Übereinstimmung mit einem einzelnen Absatz zu erzielen. Das Backtracking für „faule“ Quantoren funktioniert umgekehrt. Wenn der reguläre Ausdruck /
.*?
/ zu .*? wechselt, versucht er zunächst, sie alle zu überspringen, und sucht dann weiterhin nach .这样做是因为*?匹配零次或多次,尽可能少重复,尽可能少意味着可以重复零次。但是,当随后的<在字符串的这一点上匹配失败时,正则表达式回溯并尝试下一个最小的字符数:1个。正则表达式继续像这样向前回溯到第一段的末尾,在那里量词后面的<\/p>得到完全匹配。
如果目标字符串只有一个段落,那么此正则表达式的“贪婪”版本和“懒惰”版本是等价的,但尝试匹配的过程不同。
当一个正则表达式占用浏览器几秒甚至更长时间时,问题原因很可能是回溯失控。为说明此问题,给出下面的正则表达式,它的目标是匹配整个HTML文件。此表达式被拆分成多行是为了适合页面显示。与其他正则表达式不同,JavaScript在没有选项时可使点号匹配任意字符,包括换行符,所以此例中以[\s\S]匹配任意字符。
/<html>[\s\S]*?<head>[\s\S]*?<title>[\s\S]*?<\/title>[\s\S]*?<\/head> [\s\S]*?<body>[\s\S]*?<\/body>[\s\S]*?<\/html>/
此正则表达式匹配在正常HTML 字符串时工作良好,但当目标字符串缺少一个或多个标签时,就会变得十分糟糕。例如