Натолкнулся сегодня на «грабли», достойные, как мне кажется, чтобы написать о них мини пост.
Казалось бы, a и b должны содержать одинаковый результат, но нет.
Результат будет таков:
В объекте myRegex содержится очень хитрое свойство lastIndex, которое запоминает, в какой позиции закончился последний матч и в следующий раз начинает искать с этой позиции.
Так получается из-за того, что регулярное выражение определено с флагом g – global, который заставляет выражение ходить по всем матчам, а не только брать первый попавшийся.
Ничего не изменится, поскольку флаг этот хранится в объекте регулярного выражения а не для строки.
Вообще говоря, это совершенно нормальное поведение, которое, тем не менее, не совсем очевидно.
Можно внутри цикла каждый раз создавать новый объект регулярного выражения, потом для увеличения скорости решить вынести его определение перед циклом и отгрести.
OK:
Бага:
Поэтому нужно либо не использовать флаг g без надобности, либо не забывать перед каждым использованием выражения выставлять myRegex.lastIndex = 0;
var myRegex = /abc/gi;
var myString = "hello abc";
var a = myRegex.exec(myString);
var b = myRegex.exec(myString);
Казалось бы, a и b должны содержать одинаковый результат, но нет.
Результат будет таков:
a = ["abc"];
b = null;
В объекте myRegex содержится очень хитрое свойство lastIndex, которое запоминает, в какой позиции закончился последний матч и в следующий раз начинает искать с этой позиции.
var a = myRegex.exec(myString);
alert(myRegex.lastIndex); // 9
var b = myRegex.exec(myString);
alert(myRegex.lastIndex); // 0
Так получается из-за того, что регулярное выражение определено с флагом g – global, который заставляет выражение ходить по всем матчам, а не только брать первый попавшийся.
Что будет если работать с двумя разными строками?
Ничего не изменится, поскольку флаг этот хранится в объекте регулярного выражения а не для строки.
var myString1 = "don't say hello to abc";
var myString2 = "say hello to abc";
var a = myRegex.exec(myString1);
var b = myRegex.exec(myString2);
a // ["abc"];
b // null;
Богатая почва для фейлов.
Вообще говоря, это совершенно нормальное поведение, которое, тем не менее, не совсем очевидно.
Можно внутри цикла каждый раз создавать новый объект регулярного выражения, потом для увеличения скорости решить вынести его определение перед циклом и отгрести.
OK:
for (var i = 0; i < list.length; i++)
{
var myRegex = /abc/gi;
... myRegex.exec(...) ...
}
Бага:
var myRegex = /abc/gi;
for (var i = 0; i < list.length; i++)
{
... myRegex.exec(...) ...
}
Поэтому нужно либо не использовать флаг g без надобности, либо не забывать перед каждым использованием выражения выставлять myRegex.lastIndex = 0;