Regulärer Ausdruck, um eine Zeichenfolge zwischen zwei Zeichenfolgen in JavaScript abzurufen
Die vollständigste Lösung, die in den allermeisten Fällen funktioniert, ist die Verwendung einer Erfassungsgruppe mit einem Lazy Dot Matching-Muster . Ein Punkt .
in JavaScript-Regex stimmt jedoch nicht mit Zeilenumbruchzeichen überein. In 100% der Fälle funktioniert also ein [^]
oder [\s\S]
/ [\d\D]
/ [\w\W]
Konstrukt.
ECMAScript 2018 und neuere kompatible Lösung
In JavaScript-Umgebungen, die ECMAScript 2018 unterstützen , können mit dem s
Modifikator .
alle Zeichen einschließlich Zeilenumbruchzeichen abgeglichen werden, und die Regex-Engine unterstützt Lookbehinds mit variabler Länge. Sie können also einen regulären Ausdruck wie verwenden
var result = s.match(/(?<=cow\s+).*?(?=\s+milk)/gs); // Returns multiple matches if any
// Or
var result = s.match(/(?<=cow\s*).*?(?=\s*milk)/gs); // Same but whitespaces are optional
In beiden Fällen wird die aktuelle Position cow
mit 1/0 oder mehr Leerzeichen danach überprüft cow
, dann werden alle 0+ Zeichen so wenig wie möglich abgeglichen und verbraucht (= zum Übereinstimmungswert hinzugefügt) und dann milk
überprüft (mit einem beliebigen) 1/0 oder mehr Leerzeichen vor diesem Teilstring).
Szenario 1: Einzeilige Eingabe
Dieses und alle anderen unten aufgeführten Szenarien werden von allen JavaScript-Umgebungen unterstützt. Siehe Verwendungsbeispiele am Ende der Antwort.
cow (.*?) milk
cow
zuerst, dann ein Leerzeichen, dann alle 0+ Zeichen außer Zeilenumbruch Zeichen, so wenig wie möglich zu finden ist wie *?
ein fauler quantifier ist, werden in Gruppe 1 erfasst und dann ein Raum mit milk
folgen müssen (und die aufeinander abgestimmt sind und verbraucht auch ).
Szenario 2: Mehrzeilige Eingabe
cow ([\s\S]*?) milk
Hier wird zuerst cow
ein Leerzeichen abgeglichen, dann werden möglichst wenige 0+ Zeichen abgeglichen und in Gruppe 1 erfasst, und dann wird ein Leerzeichen mit milk
abgeglichen.
Szenario 3: Überlappende Übereinstimmungen
Wenn Sie eine Zeichenfolge wie >>>15 text>>>67 text2>>>
und Sie müssen zwei Spiele bekommen in-zwischen >>>
+ number
+ whitespace
und >>>
können Sie nicht verwenden , />>>\d+\s(.*?)>>>/g
da dies nur ein Spiel aufgrund der Tatsache , finden die >>>
zuvor 67
bereits verbraucht bei der Suche nach der ersten Partie. Sie können einen positiven Lookahead verwenden , um die Textpräsenz zu überprüfen, ohne sie tatsächlich zu "verschlingen" (dh an das Spiel anzuhängen):
/>>>\d+\s(.*?)(?=>>>)/g
Siehe die Online-Regex-Demo mit text1
undtext2
als Gruppe 1 Inhalte.
Siehe auch So erhalten Sie alle möglichen überlappenden Übereinstimmungen für eine Zeichenfolge .
Leistungsüberlegungen
Lazy Dot Matching Pattern ( .*?
) in Regex-Mustern kann die Skriptausführung verlangsamen, wenn sehr lange Eingaben gemacht werden. In vielen Fällen hilft die Unroll-the-Loop-Technik in größerem Maße. Beim Versuch, alle zwischen cow
und milk
von zu erfassen "Their\ncow\ngives\nmore\nmilk"
, sehen wir, dass wir nur alle Zeilen abgleichen müssen, die nicht mit beginnen. Daher können wir milk
stattdessen cow\n([\s\S]*?)\nmilk
Folgendes verwenden:
/cow\n(.*(?:\n(?!milk$).*)*)\nmilk/gm
Siehe die Regex-Demo (falls vorhanden \r\n
, verwenden /cow\r?\n(.*(?:\r?\n(?!milk$).*)*)\r?\nmilk/gm
). Mit dieser kleinen Testzeichenfolge ist der Leistungsgewinn vernachlässigbar, aber bei sehr großem Text werden Sie den Unterschied spüren (insbesondere wenn die Zeilen lang und die Zeilenumbrüche nicht sehr zahlreich sind).
Beispiel für die Verwendung von Regex in JavaScript:
//Single/First match expected: use no global modifier and access match[1]
console.log("My cow always gives milk".match(/cow (.*?) milk/)[1]);
// Multiple matches: get multiple matches with a global modifier and
// trim the results if length of leading/trailing delimiters is known
var s = "My cow always gives milk, thier cow also gives milk";
console.log(s.match(/cow (.*?) milk/g).map(function(x) {return x.substr(4,x.length-9);}));
//or use RegExp#exec inside a loop to collect all the Group 1 contents
var result = [], m, rx = /cow (.*?) milk/g;
while ((m=rx.exec(s)) !== null) {
result.push(m[1]);
}
console.log(result);
Mit der modernen String#matchAll
Methode
const s = "My cow always gives milk, thier cow also gives milk";
const matches = s.matchAll(/cow (.*?) milk/g);
console.log(Array.from(matches, x => x[1]));