Регулярное выражение для получения строки между двумя строками в Javascript

166

Я нашел очень похожие посты, но я не могу получить мое регулярное выражение прямо здесь.

Я пытаюсь написать регулярное выражение, которое возвращает строку, которая находится между двумя другими строками. Например: я хочу получить строку, которая находится между строками "корова" и "молоко".

Моя корова всегда дает молоко

вернется

"всегда дает"

Вот выражение, которое я сложил до сих пор:

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

Тем не менее, это возвращает строку «корова всегда дает».

Фил
источник
6
Я наткнулся на этот старый вопрос и хотел уточнить, почему testRE - это массив. test.match возвращает массив с первым индексом в качестве общего соответствия (например, строка, которая соответствует коровьему (. *) молоку), а затем все захваченные строки, такие как (. *), если бы был второй набор скобок, они бы тогда будь на testRE [2]
Salketer
4
Это решение не будет работать, если вы ищете строку, содержащую переводы строки. В таком случае вам следует использовать «STRING_ONE ([\\ s \\ S] *?) STRING_TWO». stackoverflow.com/questions/22531252/…
Майкл. Ламли
просто для справки метод сопоставления на MDN developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
vzR

Ответы:

183

Взгляд в будущее (эта (?=часть) не потребляет никакой информации. Это утверждение с нулевой шириной (как и проверка границ и просмотр за пределами).

Вы хотите регулярный матч здесь, чтобы потреблять cowчасть. Для захвата промежуточной части вы используете группу захвата (просто поместите часть шаблона, которую вы хотите захватить, в круглые скобки):

cow(.*)milk

Нет необходимости в взглядах.

Р. Мартиньо Фернандес
источник
26
Когда я проверяю это, предоставленное выражение Regex включает в себя как «корова», так и «молоко» ...
TheCascadian
4
Это пропущенный шаг. Когда вы получите результат сопоставления, вам нужно извлечь сопоставленный текст первой группы захвата matched[1], а не весь сопоставленный текст с matched[0].
Рори О'Кейн
7
В Javascript вам на самом деле нужно использовать, ([\s\S]*?)а не (.*?).
Цянь Чен
7
Хотя это полезная методика, она была отвергнута, потому что ИМХО это НЕ правильный ответ на вопрос, поскольку она включает «корову» и «молоко», как утверждает @TheCascadian
Almir Campos
@AlmirCampos - если я не ошибаюсь, нет способа сделать это сравнение без сопоставления «корова» и «молоко» (так как вы хотите сопоставить то, что находится между этими двумя). Проблема не в самом RegEx, а в том, как вы справляетесь с этим позже (как упомянул Рори О'Кейн). В противном случае вы могли бы соответствовать только для окружающих пространств - и это даст вам ОЧЕНЬ неправильный возврат, не так ли?
родился
69

Регулярное выражение для получения строки между двумя строками в JavaScript

Наиболее полное решение, которое будет работать в подавляющем большинстве случаев, - это использование группы захвата с ленивым шаблоном сопоставления точек . Тем не менее, точка .в регулярном выражении JavaScript не соответствует символам разрыва строки, поэтому в 100% случаев будет работать конструкция a [^]или [\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

Смотрите онлайн регулярное выражение демо приносит text1и text2в группе найдено 1 содержание.

Также смотрите Как получить все возможные совпадения для строки .

Вопросы производительности

Lazy dot match pattern ( .*?) внутри шаблонов регулярных выражений может замедлить выполнение скрипта, если задан очень длинный ввод. Во многих случаях техника «развернуть петлю» помогает в большей степени. Пытаясь получить все между 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);

Используя современный String#matchAllметод

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]));

Виктор Стрибьев
источник
51

Вот регулярное выражение, которое захватит то, что находится между коровой и молоком (без пробела в начале / конце):

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

Пример: http://jsfiddle.net/entropo/tkP74/

entropo
источник
17
  • Вам нужно захватить .*
  • Вы можете (но не обязаны) сделать .*нонгида
  • Там действительно не нужно смотреть вперед.

    > /cow(.*?)milk/i.exec('My cow always gives milk');
    ["cow always gives milk", " always gives "]
    
Мэтт Болл
источник
В этом конкретном случае, если бы он был жадным, он достиг бы конца и отступил (предположительно).
Бен
9

Выбранный ответ не работает для меня ... хм ...

Просто добавьте пробел после коровы и / или перед молоком, чтобы урезать пробелы из "всегда дает"

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

введите описание изображения здесь

duduwe
источник
Вам не нужно комментировать свой собственный ответ, просто отредактируйте его.
Коди G
Взгляд сзади ?<=не поддерживается в Javascript.
Марк Карпентер-младший
@MarkCarpenterJr, если вы проверили его через regextester.com , вы получите эту подсказку. Похоже, что сайт основывает свои правила на более старой спецификации. Lookbehind теперь поддерживается. См. Stackoverflow.com/questions/30118815/… И шаблон хорошо работает в современных браузерах без ошибок. Попробуйте эту проверку вместо regex101.com
Duduwe
@ CodyG.ah да. понял.
Duduwe
8

Я смог получить то, что мне было нужно, используя решение Мартино Фернандеса, приведенное ниже. Код является:

var test = "My cow always gives milk";

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

Вы заметите, что я оповещаю переменную testRE как массив. Это потому, что testRE по какой-то причине возвращается как массив. Выход из:

My cow always gives milk

Изменения в:

always gives
Фил
источник
1
Спасибо, я добавил для этого скрипку ( jsfiddle.net/MoscaPt/g5Lngjx8/2 ). / Йохан
Mosca Pt
4

Просто используйте следующее регулярное выражение:

(?<=My cow\s).*?(?=\smilk)
Brandon
источник
Взгляд сзади ?<=не поддерживается в Javascript. Был бы способ сделать это все же.
Марк Карпентер-младший
Поддерживается в JavaScript. Это не поддерживается в Safari и Mozilla (пока), только в Chrome и Opera.
Пол Струпейкис
4

Я нахожу регулярное выражение утомительным и трудоемким, учитывая синтаксис. Поскольку вы уже используете javascript, без регулярных выражений сделать следующее проще:

const text = 'My cow always gives milk'
const start = `cow`;
const end = `milk`;
const middleText = text.split(start)[1].split(end)[0]
console.log(middleText) // prints "always gives"
Чейз Олифант
источник
2
Работает для меня! фантастический ответ, потому что это действительно просто! :)
Андрей Ирвин
2

Если данные в несколько строк, то вам, возможно, придется использовать следующее,

/My cow ([\s\S]*)milk/gm

My cow always gives 
milk

Пример Regex 101

Нареш Кумар
источник
0

Метод match () ищет в строке совпадение и возвращает объект Array.

// 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

задача

Извлечь подстроку между двумя строками (исключая эти две строки)

Решение

let allText = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum";
let textBefore = "five centuries,";
let textAfter = "electronic typesetting";
var regExp = new RegExp(`(?<=${textBefore}\\s)(.+?)(?=\\s+${textAfter})`, "g");
var results = regExp.exec(allText);
if (results && results.length > 1) {
    console.log(results[0]);
}
Василий Боднарчук
источник