Регулярний вираз для отримання рядка між двома рядками в JavaScript
Найповнішим рішенням, яке буде працювати в переважній більшості випадків, є використання групи захоплення з ледачим зразком узгодження крапок . Тим НЕ менше, точка .
в JavaScript регулярний вираз не відповідає символи перекладу рядків, так, що буде працювати в 100% випадків є [^]
або [\s\S]
/ [\d\D]
/ [\w\W]
конструкції.
ECMAScript 2018 та новіші сумісні рішення
У середовищах JavaScript, що підтримують ECMAScript 2018 , s
модифікатор дозволяє .
відповідати будь-яким знакам, включаючи символи розриву рядків, а двигун regex підтримує вигляд із змінною довжиною. Отже, ви можете використовувати подібний регулярний вираз
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 зміст.
Також див. Як отримати всі можливі збіги, що перетинаються для рядка .
Міркування щодо продуктивності
Лінивий шаблон узгодження точок ( .*?
) всередині шаблонів регулярних виразів може сповільнити виконання сценарію, якщо буде введено дуже довге введення У багатьох випадках техніка розкручування допомагає більшою мірою. Намагаючись схопити все між cow
і milk
з "Their\ncow\ngives\nmore\nmilk"
, ми бачимо, що нам просто потрібно відповідати всі рядки, які не починаються з milk
, таким чином, замість цього cow\n([\s\S]*?)\nmilk
ми можемо використовувати:
/cow\n(.*(?:\n(?!milk$).*)*)\nmilk/gm
Перегляньте демонстраційну виразку (якщо є \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]));