Espressione regolare per ottenere una stringa tra due stringhe in JavaScript
La soluzione più completa che funzionerà nella stragrande maggioranza dei casi è l'utilizzo di un gruppo di acquisizione con un modello di corrispondenza punti pigro . Tuttavia, un punto .in regex JavaScript non corrisponde ai caratteri di interruzione di riga, quindi ciò che funzionerà nel 100% dei casi è un [^]o [\s\S]/ [\d\D]/ [\w\W]costrutti.
ECMAScript 2018 e soluzione compatibile più recente
Negli ambienti JavaScript che supportano ECMAScript 2018 , il smodificatore consente .di abbinare qualsiasi carattere, inclusi i caratteri di interruzione di riga, e il motore regex supporta lookbehind di lunghezza variabile. Quindi, puoi usare un regex come
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 entrambi i casi, la posizione corrente viene controllata cowcon 1/0 o più spazi bianchi dopo cow, quindi ogni 0+ caratteri il meno possibile vengono abbinati e consumati (= aggiunti al valore di corrispondenza), quindi milkviene verificato (con qualsiasi 1/0 o più spazi bianchi prima di questa sottostringa).
Scenario 1: input a riga singola
Questo e tutti gli altri scenari di seguito sono supportati da tutti gli ambienti JavaScript. Vedi esempi di utilizzo in fondo alla risposta.
cow (.*?) milk
cowsi trova, poi uno spazio, allora qualsiasi 0+ caratteri diversi da caratteri di interruzione di riga, il meno possibile, come *?è un quantificatore pigrizia, vengono catturati in gruppo 1 e quindi uno spazio con milkdeve seguire (e quelli sono abbinati e consumati , troppo ).
Scenario 2: input multilinea
cow ([\s\S]*?) milk
Qui, cowe uno spazio viene prima abbinato, quindi ogni 0+ caratteri il meno possibile vengono abbinati e catturati nel Gruppo 1, e quindi uno spazio con milkviene abbinato.
Scenario 3: partite sovrapposte
Se hai una stringa simile >>>15 text>>>67 text2>>>e hai bisogno di ottenere 2 corrispondenze tra >>>+ number+ whitespacee >>>, non puoi usarlo />>>\d+\s(.*?)>>>/gpoiché questo troverà solo 1 corrispondenza a causa del fatto che il >>>precedente 67è già consumato quando trova la prima corrispondenza. È possibile utilizzare un lookahead positivo per verificare la presenza del testo senza effettivamente "divorarlo" (ovvero accodando alla corrispondenza):
/>>>\d+\s(.*?)(?=>>>)/g
Guarda la resa in linea di regex onlinetext1 e text2come contenuto del Gruppo 1 trovato.
Vedi anche Come ottenere tutte le possibili corrispondenze sovrapposte per una stringa .
Considerazioni sulle prestazioni
Il pattern di corrispondenza dei punti pigri ( .*?) all'interno dei pattern regex può rallentare l'esecuzione dello script se viene fornito un input molto lungo. In molti casi, la tecnica di svolgimento del ciclo aiuta in misura maggiore. Cercando di afferrare tutto tra cowe milkda "Their\ncow\ngives\nmore\nmilk", vediamo che dobbiamo solo abbinare tutte le linee che non iniziano con milk, quindi, invece di cow\n([\s\S]*?)\nmilkpoter usare:
/cow\n(.*(?:\n(?!milk$).*)*)\nmilk/gm
Guarda la demo di regex (se possibile \r\n, usa /cow\r?\n(.*(?:\r?\n(?!milk$).*)*)\r?\nmilk/gm). Con questa piccola stringa di prova, il guadagno in termini di prestazioni è trascurabile, ma con un testo molto grande, sentirai la differenza (specialmente se le linee sono lunghe e le interruzioni di riga non sono molto numerose).
Esempio di utilizzo di 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);
Utilizzando il String#matchAllmetodo moderno
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]));