Выразительный JavaScript (Хавербеке) - страница 100

>// → 2

>console.log(" ".search(/\S/));

>// → -1

К сожалению, никак нельзя задать, чтобы метод искал совпадение, начиная с конкретного смещения (как это можно сделать с >indexOf). Это было бы полезно.

Свойство lastIndex

Метод exec тоже не даёт удобного способа начать поиск с заданной позиции в строке. Но неудобный способ даёт.

У объекта регулярок есть свойства. Одно из них – >source, содержащее строку. Ещё одно – >lastIndex, контролирующее, в некоторых условиях, где начнётся следующий поиск вхождений.

Эти условия включают необходимость присутствия глобальной опции >g, и то, что поиск должен идти с применением метода >exec. Более разумным решением было бы просто допустить дополнительный аргумент для передачи в >exec, но разумность – не основополагающая черта в интерфейсе регулярок JavaScript.

>var pattern = /y/g;

>pattern.lastIndex = 3;

>var match = pattern.exec("xyzzy");

>console.log(match.index);

>// → 4

>console.log(pattern.lastIndex);

>// → 5

Если поиск был успешным, вызов >exec обновляет свойство >lastIndex, чтобы оно указывало на позицию после найденного вхождения. Если успеха не было, >lastIndex устанавливается в ноль – как и >lastIndex у только что созданного объекта.

При использовании глобальной переменной-регулярки и нескольких вызовов >exec эти автоматические обновления >lastIndex могут привести к проблемам. Ваша регулярка может начать поиск с позиции, оставшейся с предыдущего вызова.

>var digit = /\d/g;

>console.log(digit.exec("here it is: 1"));

>// → ["1"]

>console.log(digit.exec("and now: 1"));

>// → null

Ещё один интересный эффект опции >g в том, что она меняет работу метода >match. Когда он вызывается с этой опцией, вместо возврата массива, похожего на результат работы >exec, он находит все вхождения шаблона в строке и возвращает массив из найденных подстрок.

>console.log("Банан".match(/ан/g));

>// → ["ан", "ан"]

Так что поосторожнее с глобальными переменными-регулярками. В случаях, когда они необходимы – вызовы >replace или места, где вы специально используете >lastIndex – пожалуй и все случаи, в которых их следует применять.

Циклы по вхождениям

Типичная задача – пройти по всем вхождениям шаблона в строку так, чтобы иметь доступ к объекту >match в теле цикла, используя >lastIndex и >exec.

>var input = "Строчка с 3 числами в ней... 42 и 88.";

>var number = /\b(\d+)\b/g;

>var match;

>while (match = number.exec(input))

>  console.log("Нашёл ", match[1], " на ", match.index);

>// → Нашёл 3 на 10

>//   Нашёл 42 на 29

>//   Нашёл 88 на 34

Используется тот факт, что значением присвоения является присваиваемое значение. Используя конструкцию