web-dev-qa-db-ger.com

Regulärer Ausdruck, um eine Zeichenfolge zwischen zwei Zeichenfolgen in Javascript abzurufen

Ich habe sehr ähnliche Beiträge gefunden, aber ich kann meinen regulären Ausdruck hier nicht richtig verstehen.

Ich versuche, einen regulären Ausdruck zu schreiben, der eine Zeichenfolge zurückgibt, die zwischen zwei anderen Zeichenfolgen liegt. Zum Beispiel: Ich möchte den String erhalten, der sich zwischen den Strings "cow" und "milk" befindet.

Meine Kuh gibt immer Milch

würde zurückkehren

"gibt immer"

Hier ist der Ausdruck, den ich bisher zusammengesetzt habe:

(?=cow).*(?=milk)

Dies gibt jedoch die Zeichenfolge "Kuh gibt immer" zurück.

131
phil

Ein Lookahead (das (?= part) verbraucht keine Eingabe. Es ist eine Behauptung mit der Breite Null (wie auch Grenzüberprüfungen und Lookbehinds).

Sie möchten hier eine reguläre Übereinstimmung, um den Teil cow zu verbrauchen. Um den Teil dazwischen zu erfassen, verwenden Sie eine Erfassungsgruppe (fügen Sie einfach den Teil des Musters, den Sie erfassen möchten, in Klammern ein):

cow(.*)milk

Es werden überhaupt keine Lookaheads benötigt.

153

Regulärer Ausdruck, um eine Zeichenfolge zwischen zwei Zeichenfolgen in JavaScript abzurufen

Die umfassendste 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 Zeilenumbrüchen überein. In 100% der Fälle ist also ein [^] Oder [\s\S]/[\d\D]/[\w\W] Konstrukte.

ECMAScript 2018 und neuere kompatible Lösung

In JavaScript-Umgebungen, die ECMAScript 2018 unterstützen, ermöglicht der Modifikator s, dass . Mit allen Zeichen einschließlich Zeilenumbruchzeichen übereinstimmt, und die Regex-Engine unterstützt Lookbehinds variabler Länge. Sie können also einen regulären Ausdruck 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 mit 1/0 oder mehr Leerzeichen nach cow auf cow überprüft, und dann werden mindestens 0 Zeichen abgeglichen und verbraucht (= zu den Zeichen hinzugefügt) match value), und dann wird milk überprüft (mit 1/0 oder mehr Leerzeichen vor dieser Teilzeichenfolge).

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 wird zuerst gefunden, dann ein Leerzeichen, dann werden alle 0+ Zeichen außer Zeilenumbruchzeichen, so wenig wie möglich, wie *? ein verzögerter Quantifizierer ist, in Gruppe 1 und dann ein Leerzeichen erfasst mit milk muss folgen (und diese werden abgeglichen und verbraucht auch).

Szenario 2: Mehrzeilige Eingabe

cow ([\s\S]*?) milk

Hier werden zuerst cow und ein Leerzeichen abgeglichen, dann werden mindestens 0 Zeichen abgeglichen und in Gruppe 1 erfasst, und dann wird ein Leerzeichen mit milk abgeglichen.

Szenario 3: Überlappende Übereinstimmungen

Wenn Sie einen String wie >>>15 text>>>67 text2>>> Haben und 2 Übereinstimmungen zwischen >>> + number + whitespace und >>> Erhalten müssen, Sie können />>>\d+\s(.*?)>>>/g nicht verwenden, da dies nur eine Übereinstimmung findet, da >>> vor 67 steht bereits verbraucht beim Finden der ersten Übereinstimmung. Sie können einen positiven Lookahead verwenden, um die Textpräsenz zu überprüfen, ohne sie tatsächlich zu "verschlingen" (d. H an das Spiel anhängen):

/>>>\d+\s(.*?)(?=>>>)/g

Sehen Sie sich die Online-Regex-Demo an, die text1 Und text2 Als Inhalt von Gruppe 1 ergibt.

Siehe auch Wie man alle möglichen überlappenden Übereinstimmungen für einen String erhält .

Leistungsaspekte

Lazy-Dot-Matching-Muster (.*?) In Regex-Mustern können die Skriptausführung verlangsamen, wenn sehr lange Eingaben gemacht werden. In vielen Fällen hilft Unroll-the-Loop-Technik in größerem Maße. Beim Versuch, alle zwischen cow und milk aus "Their\ncow\ngives\nmore\nmilk" Zu holen, müssen wir nur alle Zeilen abgleichen, die nicht mit milk beginnen. Anstelle von cow\n([\s\S]*?)\nmilk können wir verwenden:

/cow\n(.*(?:\n(?!milk$).*)*)\nmilk/gm

Siehe die Regex-Demo (wenn es \r\n Geben kann, benutze /cow\r?\n(.*(?:\r?\n(?!milk$).*)*)\r?\nmilk/gm). Bei dieser kleinen Testzeichenfolge ist der Leistungszuwachs vernachlässigbar, aber bei sehr großem Text werden Sie den Unterschied bemerken (insbesondere, wenn die Zeilen lang sind 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);
55

Hier ist ein regulärer Ausdruck, der festhält, was sich zwischen Kuh und Milch befindet (ohne führende/nachfolgende Leerstelle):

srctext = "My cow always gives milk.";
var re = /(.*cow\s+)(.*)(\s+milk.*)/;
var newtext = srctext.replace(re, "$2");

Ein Beispiel: http://jsfiddle.net/entropo/tkP74/

50
entropo
  • Sie müssen den .* Erfassen
  • Sie können (müssen aber nicht) den .* - Fehler machen
  • Der Lookahead ist wirklich nicht nötig.

    > /cow(.*?)milk/i.exec('My cow always gives milk');
    ["cow always gives milk", " always gives "]
    
15
Matt Ball

Mit der folgenden Lösung von Martinho Fernandes konnte ich das bekommen, was ich brauchte. Der Code lautet:

var test = "My cow always gives milk";

var testRE = test.match("cow(.*)milk");
alert(testRE[1]);

Sie werden feststellen, dass ich die Variable testRE als Array alarmiere. Dies liegt daran, dass testRE aus irgendeinem Grund als Array zurückgegeben wird. Die Ausgabe von:

My cow always gives milk

Änderungen in:

always gives
7
phil

Die gewählte Antwort hat bei mir nicht funktioniert ... hmm ...

Fügen Sie einfach Platz nach der Kuh und/oder vor der Milch hinzu, um Leerzeichen von "immer gibt" zu entfernen.

/(?<=cow ).*(?= milk)/

enter image description here

6
duduwe

Verwenden Sie einfach den folgenden regulären Ausdruck:

(?<=My cow\s).*?(?=\smilk)
4
Brandon

Die Methode match () durchsucht einen String nach einer Übereinstimmung und gibt ein Array-Objekt zurück.

// Original string
var str = "My cow always gives milk";

// Using index [0] would return<br/>
// "**cow always gives milk**"
str.match(/cow(.*)milk/)**[0]**


// Using index **[1]** would return
// "**always gives**"
str.match(/cow(.*)milk/)[1]
0
Marc Antoni