JavaScript регулярные выражения и суб-совпадения - PullRequest
65 голосов
/ 10 мая 2009

Почему вспомогательные совпадения Javascript перестают работать, если установлен модификатор g?

var text = 'test test test test';

var result = text.match(/t(e)(s)t/);
// Result: ["test", "e", "s"]

Выше работает нормально, result[1] это "e" и result[2] это "s".

var result = text.match(/t(e)(s)t/g);
// Result: ["test", "test", "test", "test"]

Выше игнорируются мои группы захвата. Является ли следующее единственно верным решением?

var result = text.match(/test/g);
for (var i in result) {
    console.log(result[i].match(/t(e)(s)t/));
}
/* Result:
["test", "e", "s"]
["test", "e", "s"]
["test", "e", "s"]
["test", "e", "s"]
*/

EDIT:

Я снова рад сообщить вам, что через 10 лет вы можете сделать это (.matchAll был добавлен в спецификацию)

let result = [...text.matchAll(/t(e)(s)t/g)];

Ответы [ 2 ]

94 голосов
/ 10 мая 2009

Использование функции String match() не будет возвращать захваченные группы, если установлен глобальный модификатор, как вы узнали.

В этом случае вы захотите использовать объект RegExp и вызвать его функцию exec(). String s match() почти идентичен функции RegExp s exec() ... за исключением случаев, подобных этим. Если установлен глобальный модификатор, обычная функция match() не будет возвращать захваченные группы, а функция RegExp exec(). (Отмечено здесь , среди других мест.)

Еще один улов, который следует помнить, это то, что exec() не возвращает совпадения в одном большом массиве - он продолжает возвращать совпадения, пока не закончится, и в этом случае он возвращает null.

Так, например, вы можете сделать что-то вроде этого:

var pattern = /t(e)(s)t/g;  // Alternatively, "new RegExp('t(e)(s)t', 'g');"
var match;    

while (match = pattern.exec(text)) {
    // Do something with the match (["test", "e", "s"]) here...
}

Следует также отметить, что RegExp.prototype.exec() и RegExp.prototype.test() выполняют регулярное выражение в предоставленной строке и возвращают первый результат. Каждый последовательный вызов будет проходить через обновление набора результатов RegExp.prototype.lastIndex на основе текущей позиции в строке.

Вот пример: // помните, что в примере и шаблоне 4 совпадения. lastIndex начинается с 0

pattern.test(text); // pattern.lastIndex = 4
pattern.test(text); // pattern.lastIndex = 9
pattern.exec(text); // pattern.lastIndex = 14
pattern.exec(text); // pattern.lastIndex = 19

// if we were to call pattern.exec(text) again it would return null and reset the pattern.lastIndex to 0
while (var match = pattern.exec(text)) {
    // never gets run because we already traversed the string
    console.log(match);
}

pattern.test(text); // pattern.lastIndex = 4
pattern.test(text); // pattern.lastIndex = 9

// however we can reset the lastIndex and it will give us the ability to traverse the string from the start again or any specific position in the string
pattern.lastIndex = 0;

while (var match = pattern.exec(text)) {
    // outputs all matches
    console.log(match);
}

Вы можете найти информацию о том, как использовать RegExp объекты в MDN (в частности, вот документация для функции exec() ).

1 голос
/ 15 мая 2019

Я удивлен, увидев, что я первый, кто ответил на этот вопрос тем ответом, который искал 10 лет назад (ответа еще не было). Я также надеялся, что настоящие авторы спецификаций ответили бы до меня;).

.matchAll уже добавлено в несколько браузеров.

В современном javascript мы можем сделать это, просто выполнив следующее.

let result = [...text.matchAll(/t(e)(s)t/g)];

.matchAll spec

.matchAll документы

Теперь я поддерживаю изоморфную библиотеку javascript, которая помогает во многих видах синтаксического анализа строк. Вы можете проверить это здесь: ленточная пила . Это помогает упростить использование .matchAll при использовании именованных групп захвата.

Примером будет

saw(text).matchAll(/t(e)(s)t/g)

Который выводит более удобный для пользователя массив совпадений, и если вы хотите получить фантазию, вы можете добавить именованные группы захвата и получить массив объектов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...