Регулярное выражение для получения строки между двумя строками в JavaScript
Наиболее полное решение, которое будет работать в подавляющем большинстве случаев, - это использование группы захвата с шаблоном сопоставления ленивых точек .Однако точка .
в регулярном выражении JavaScript не соответствует символам разрыва строки, поэтому в 100% случаев будут работать конструкции [^]
или [\s\S]
/ [\d\D]
/ [\w\W]
.
ECMAScript 2018 и более новые совместимые решения
В средах JavaScript с поддержкой ECMAScript 2018 , s
позволяет .
соответствовать любому символу, включая символы разрыва строки, а механизм регулярных выражений поддерживает просмотр за пределамиПеременная длинаТаким образом, вы можете использовать регулярное выражение, например
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
. В обоих случаях текущая позиция проверяется на cow
с любыми 1/0 или более пробелами после cow
, а затем с любым 0+ символом, как малонасколько возможно, сопоставляются и потребляются (= добавляются к значению совпадения), а затем проверяется наличие milk
(с любыми 1/0 или более пробелами перед этой подстрокой).
Сценарий 1: однострочный ввод
Этот и все приведенные ниже сценарии поддерживаются всеми средами JavaScript.См. Примеры использования внизу ответа.
cow (.*?) milk
cow
находится сначала, затем пробел, затем любые 0+ символов, кроме символов разрыва строки, всего нескольковозможно, так как *?
является ленивым квантификатором, попадает в Группу 1, а затем должен следовать пробел с milk
(и они совпадают, и также потребляется ).
Сценарий 2: Многострочный ввод
cow ([\s\S]*?) milk
Здесь cow
и пробел сначала сопоставляются, затем любые 0+ символов, как можно меньше, сопоставляются и записываются в группу 1, а затем пробел с milk
Сценарий 3: перекрывающиеся совпадения
Если у вас есть строка типа >>>15 text>>>67 text2>>>
и вам нужно получить 2 совпадения между >>>
+ number
+ whitespace
и>>>
, вы не можете использовать />>>\d+\s(.*?)>>>/g
, так как при этом будет найдено только 1 совпадение из-за того, что >>>
до 67
уже потреблено при нахождении первогоматч.Вы можете использовать положительный взгляд , чтобы проверить наличие текста без фактического «сожрания» его (т. Е. Добавления к совпадению):
/>>>\d+\s(.*?)(?=>>>)/g
См. online regex demo с результатом text1
и text2
в качестве найденного содержимого группы 1.
Также см. Как получить все возможные совпадения совпадений для строки .
Вопросы производительности
Шаблон сопоставления с отложенными точками (.*?
) внутри шаблонов регулярных выражений может замедлить выполнение сценария, если задан очень длинный ввод.Во многих случаях метод развернутой петли помогает в большей степени.Пытаясь захватить все между cow
и milk
из "Their\ncow\ngives\nmore\nmilk"
, мы видим, что нам просто нужно сопоставить все строки, которые не начинаются с milk
, таким образом, вместо cow\n([\s\S]*?)\nmilk
мыможно использовать:
/cow\n(.*(?:\n(?!milk$).*)*)\nmilk/gm
См. демонстрационную версию regex (если может быть \r\n
, используйте /cow\r?\n(.*(?:\r?\n(?!milk$).*)*)\r?\nmilk/gm
).С этой небольшой тестовой строкой прирост производительности незначителен, но при очень большом тексте вы почувствуете разницу (особенно если строки длинные, а разрывы строк не очень многочисленны).
Пример регулярного выраженияиспользование в 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);