Wyrażenie regularne do pobrania ciągu między dwoma ciągami w JavaScript
Najbardziej kompletnym rozwiązaniem, które będzie działać w zdecydowanej większości przypadków, jest użycie grupy przechwytywania z leniwym wzorem dopasowywania kropek . Jednak kropka .
w wyrażeniu regularnym JavaScript nie pasuje do znaków końca wiersza, więc to, co zadziała w 100%, to konstrukcja [^]
lub [\s\S]
/ [\d\D]
/ [\w\W]
.
ECMAScript 2018 i nowsze kompatybilne rozwiązanie
W środowisku JavaScript podtrzymujących ECMAScript 2018 , s
modyfikatora umożliwia .
dopasowanie wszystkich char tym włamaniowych linii znaków i regex wsporniki silnika lookbehinds o zmiennej długości. Możesz więc użyć wyrażenia regularnego, takiego jak
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
W obu przypadkach bieżąca pozycja jest sprawdzana za cow
pomocą 1/0 lub więcej białych znaków po cow
, a następnie dowolne 0+ znaków tak mało, jak to możliwe, jest dopasowywane i konsumowane (= dodawane do wartości dopasowania), a następnie milk
sprawdzane pod kątem (z dowolnymi 1/0 lub więcej białych znaków przed tym podciągiem).
Scenariusz 1: wejście jednoliniowe
Ten i wszystkie inne poniższe scenariusze są obsługiwane przez wszystkie środowiska JavaScript. Zobacz przykłady użycia na dole odpowiedzi.
cow (.*?) milk
cow
znaleziono, następnie miejsce, wtedy każdy 0+ znaki inne niż linia przerwy znaków, tak mało jak to możliwe, jak *?
to leniwa kwantyfikator, są ujęte w grupy 1, a następnie z przestrzeni milk
muszą przestrzegać (oraz są dopasowane i spożywane zbyt ).
Scenariusz 2: wejście wieloliniowe
cow ([\s\S]*?) milk
Tutaj cow
i spacja są najpierw dopasowywane, następnie dowolne 0+ znaków, jak najmniej, jest dopasowywanych i przechwytywanych do grupy 1, a następnie spacja z milk
jest dopasowywana.
Scenariusz 3: Pokrywające się mecze
Jeśli masz taki ciąg >>>15 text>>>67 text2>>>
i chcesz uzyskać 2 dopasowania pomiędzy >>>
+ number
+ whitespace
i >>>
, nie możesz użyć, />>>\d+\s(.*?)>>>/g
ponieważ spowoduje to znalezienie tylko 1 dopasowania, ponieważ >>>
poprzednia 67
jest już zużyta po znalezieniu pierwszego dopasowania. Możesz użyć pozytywnego lookahead, aby sprawdzić obecność tekstu bez faktycznego „pożerania” go (tj. Dołączania do dopasowania):
/>>>\d+\s(.*?)(?=>>>)/g
Zobacz demo regex Internecie plonowanie text1
i text2
jako Grupa 1 znalezionych zawartość.
Zobacz także Jak uzyskać wszystkie możliwe nakładające się dopasowania dla ciągu .
Uwagi dotyczące wydajności
Leniwy wzorzec dopasowania kropek ( .*?
) wewnątrz wzorców regex może spowolnić wykonywanie skryptu, jeśli podano bardzo długie dane wejściowe. W wielu przypadkach technika rozwijania pętli pomaga w większym stopniu. Próbując złapać wszystko pomiędzy cow
i milk
z "Their\ncow\ngives\nmore\nmilk"
, widzimy, że musimy dopasować wszystkie linie, które nie zaczynają się od milk
, więc zamiast cow\n([\s\S]*?)\nmilk
możemy użyć:
/cow\n(.*(?:\n(?!milk$).*)*)\nmilk/gm
Zobacz demo wyrażeń regularnych (jeśli istnieje \r\n
, użyj /cow\r?\n(.*(?:\r?\n(?!milk$).*)*)\r?\nmilk/gm
). W przypadku tego małego ciągu testowego wzrost wydajności jest pomijalny, ale w przypadku bardzo dużego tekstu poczujesz różnicę (zwłaszcza jeśli linie są długie, a znaki końca linii nie są zbyt liczne).
Przykładowe użycie wyrażenia regularnego w 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);
Stosując nowoczesną String#matchAll
metodę
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]));