Скажем, у меня есть строка
"12345"
Если я .match(/\d{3}/g)
, я получаю только одно совпадение, "123"
. Почему я не получаю [ "123", "234", "345" ]
?
Скажем, у меня есть строка
"12345"
Если я .match(/\d{3}/g)
, я получаю только одно совпадение, "123"
. Почему я не получаю [ "123", "234", "345" ]
?
Вы не можете сделать это с помощью регулярного выражения, но вы можете получить довольно близко:
var pat = /(?=(\d{3}))\d/g;
var results = [];
var match;
while ( (match = pat.exec( '1234567' ) ) != null ) {
results.push( match[1] );
}
console.log(results);
Когда выражение совпадает, оно обычно потребляет совпадающие символы. Таким образом, после того, как выражение соответствует 123
, остается только 45
, что не соответствует шаблону.
string#match
с глобальным флагом regex возвращает массив согласованных подстрок. Регулярное выражение /\d{3}/g
соответствует и потребляет (= считывает в буфер и продвигает свой индекс в позицию сразу после совпадающего символа) 3-значная последовательность. Таким образом, после "съедания" 123
индекс расположен после 3
, и единственная подстрока, оставшаяся для синтаксического анализа, 45
- здесь не соответствует.
Я думаю, что метод , используемый в regex101.com, также стоит рассмотреть здесь: используйте утверждение с нулевой шириной (положительный просмотр с группой захвата) для проверки всех позиций внутри входной строки. После каждого теста RegExp.lastIndex
(это свойство целочисленного чтения/записи регулярных выражений, которое указывает индекс, с которого начинается следующее совпадение) продвигается "вручную", чтобы избежать бесконечного цикла.
Обратите внимание, что это метод, реализованный в .NET(Regex.Matches
), Python (re.findall
), PHP (preg_match_all
).
Вот демо:
var re = /(?=(\d{3}))/g;
var str = '12345';
var res = [];
var m;
while ((m = re.exec(str)) !== null) {
if (m.index === re.lastIndex) {
re.lastIndex++;
}
res.push(m[1]);
}
document.body.innerHTML = JSON.stringify(res);
Чтобы ответить на "Как", вы можете вручную изменить индекс последнего совпадения (требуется цикл):
var input = '12345',
re = /\d{3}/g,
r = [],
m;
while (m = re.exec(input)) {
re.lastIndex -= m[0].length - 1;
r.push(m[0]);
}
r; // ["123", "234", "345"]
Вот функция для удобства:
function matchOverlap(input, re) {
var r = [], m;
// prevent infinite loops
if (!re.global) re = new RegExp(
re.source, (re+'').split('/').pop() + 'g'
);
while (m = re.exec(input)) {
re.lastIndex -= m[0].length - 1;
r.push(m[0]);
}
return r;
}
Примеры использования:
matchOverlap('12345', /\D{3}/) // []
matchOverlap('12345', /\d{3}/) // ["123", "234", "345"]
matchOverlap('12345', /\d{3}/g) // ["123", "234", "345"]
matchOverlap('1234 5678', /\d{3}/) // ["123", "234", "567", "678"]
matchOverlap('LOLOL', /lol/) // []
matchOverlap('LOLOL', /lol/i) // ["LOL", "LOL"]
Используйте (?=(\w{3}))
(3 - количество букв в последовательности)