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 s
modificatore 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 cow
con 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 milk
viene 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
cow
si 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 milk
deve seguire (e quelli sono abbinati e consumati , troppo ).
Scenario 2: input multilinea
cow ([\s\S]*?) milk
Qui, cow
e uno spazio viene prima abbinato, quindi ogni 0+ caratteri il meno possibile vengono abbinati e catturati nel Gruppo 1, e quindi uno spazio con milk
viene abbinato.
Scenario 3: partite sovrapposte
Se hai una stringa simile >>>15 text>>>67 text2>>>
e hai bisogno di ottenere 2 corrispondenze tra >>>
+ number
+ whitespace
e >>>
, non puoi usarlo />>>\d+\s(.*?)>>>/g
poiché 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 text2
come 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 cow
e milk
da "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]*?)\nmilk
poter 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#matchAll
metodo 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]));