Подтвердить что ты не робот

Как я могу совместить перекрывающиеся строки с регулярным выражением?

Скажем, у меня есть строка

"12345"

Если я .match(/\d{3}/g), я получаю только одно совпадение, "123". Почему я не получаю [ "123", "234", "345" ]?

4b9b3361

Ответ 1

Вы не можете сделать это с помощью регулярного выражения, но вы можете получить довольно близко:

var pat = /(?=(\d{3}))\d/g;
var results = [];
var match;

while ( (match = pat.exec( '1234567' ) ) != null ) { 
  results.push( match[1] );
}

console.log(results);

Ответ 2

Когда выражение совпадает, оно обычно потребляет совпадающие символы. Таким образом, после того, как выражение соответствует 123, остается только 45, что не соответствует шаблону.

Ответ 3

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

Ответ 4

Чтобы ответить на "Как", вы можете вручную изменить индекс последнего совпадения (требуется цикл):

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"]

Ответ 5

Используйте (?=(\w{3}))

(3 - количество букв в последовательности)