Это действительно ожидаемое поведение, хотите верьте, хотите нет.Метод exec()
в регулярном выражении JavaScript является состоянием и предназначен для того, чтобы вызывать его в цикле.Каждое последующее выполнение будет возвращать следующее совпадение в строке до тех пор, пока не будет найдено никаких совпадений, и в этот момент будет возвращено значение null
.
Чтобы подчеркнуть это в вашем первом примере, давайте быстро немного упростим код ипоказать, какие значения есть в каждой переменной.
let testRegex = /yolo .+ .+/gu;
let test = [
"yolo 2 abc",
"yolo 2 abc"
]
В результате ваши вызовы testRegex.exec
будут выглядеть примерно так:
testRegex.exec("yolo 2 abc") // => Array ["yolo 2 abc"]
testRegex.exec("yolo 2 abc") // => null
Вы найдете официальную документацию по этому вопросу. здесь где они заявляют:
Если ваше регулярное выражение использует флаг "g", вы можете использовать метод exec()
несколько раз, чтобы найти последовательные совпадения в одной и той же строке.При этом поиск начинается с подстроки str
, указанной в свойстве lastIndex
регулярного выражения (test()
также будет продвигать свойство lastIndex
).Обратите внимание, что свойство lastIndex
не будет сброшено при поиске другой строки, оно начнет поиск с существующей lastIndex
.
Причина, по которой второй приведенный вами пример не встречаетсяэта проблема заключается в том, что функция match()
сбрасывает свойство lastIndex
на внутреннее значение 0, сбрасывая местоположение поиска и приводя к второму вызову exec()
поиска с начала регулярного выражения.
Возвращениек исходному примеру вы можете изменить его следующим образом и увидеть ожидаемое поведение:
var testRegex = /yolo .+ .+/gu;
let test = `yolo 2 abc
yolo 2 abc`;
test = test.split('\n');
for (let t=0; t < test.length; t++)
{
console.log(test[t], testRegex.exec(test[t]));
testRegex.lastIndex = 0;
}