2013-03-21 2 views
8

создать объект RegExp (в JavaScript), чтобы проверить на наличие ряда:Неожиданное Javascript RegExp поведение

var test = new RegExp('[0-9]', 'g'); 

Я использую его как этот

console.log(test.test('0')); // true 
console.log(test.test('1')); // false - why? 

Выход этого даже более запутанным:

console.log(test.test('1')); // true 
console.log(test.test('0')); // false - why? 
console.log(test.test('1')); // true 
console.log(test.test('2')); // false - why? 
console.log(test.test('2')); // true - correct, but why is this one true? 

Если удалить g спецификатор, он ведет себя так, как ожидалось.

Является ли это ошибкой, как я считаю, или какой-то своеобразной частью спецификации? Должен ли использоваться этот определитель g? (Я повторно использую одно и то же выражение для нескольких задач, следовательно, имея квалификатор вообще)

ответ

6

За документации: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/RegExp/test#Description

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

Вы можете подтвердить это поведение:

var test = new RegExp('[0-9]', 'g'); 
test.test('01'); //true 
test.test('01'); //true 
test.test('01'); //false 

Это не имеет смысла использовать g флаг, если все, что вы хотите, чтобы подтвердить один матч против различных строк.

+0

Спасибо. Вы были на пару минут после jfriend00, но это похоже на более полный ответ. Просто ждать окончания отсчета, чтобы согласиться! – Dave

5

Удалить флаг 'g'. Когда вы используете флаг 'g ', он обновляет свойство регулярного выражения(подготовка к последующему поиску в той же строке), а затем запускает следующий поиск из этого значения индекса (таким образом, вы даете ложное показание при следующем поиске).

Похожий вопрос и ответ здесь: Why is Regex Javascript //g flag affecting state?

+0

ли вы имеете в виду, что игнорирует строку ввода второй раз, когда я называю его, и продолжает искать совпадения в ранее заданной строке ? Это довольно странно – Dave

+0

@Dave. Он обновляет свойство lastIndex в объекте regex и запускает второе совпадение, которое дает вам ложное чтение. – jfriend00

+0

А я, кажется, сейчас понимаю. Я поставил быстрый тест вместе, и кажется, что он использует новую строку, но ищет из последнего сопоставленного индекса: http://jsfiddle.net/SnxSg/ Это должно быть самое странное поведение, но, по крайней мере, я понимаю сейчас. Благодаря! – Dave

0

Согласно MDN,

Как exec (или в сочетании с ним), test вызывается несколько раз на тот же глобальный обычный экземпляр выражения будет продвигаться мимо предыдущего матча.

Технически ECMAScript 5.1 спецификация говорит

15.10.6.3 RegExp.prototype.test (строка)

приняты следующие шаги:

  1. Пусть матч будет результат вычисления алгоритма RegExp.prototype.exec (15.10.6.2) на этом объекте RegExp с использованием строка как аргумент .
  2. Если соответствует не имеет значения null, значит возврат true; else return false.

15.10.6.2 RegExp.prototype.exec (строка)

выполняет регулярное выражение матч строки против регулярного выражения и возвращает объект массив, содержащий результаты матча или null если строка не совпала.

Строка ToString (строка) ищется для возникновения регулярного выражения следующим образом:

  1. Пусть R быть этим объектом RegExp.
  2. [...]
  3. [...]
  4. Пусть LastIndex быть результатом вызова [[Get]] внутренний метод R с аргументом "lastIndex".
  5. Позвольте i быть значением ToInteger (lastIndex).
  6. Пусть глобальный быть результатом вызова [[Get]] внутренний метод R с аргументом «global».
  7. Если глобальная является false, то пусть я = 0.
  8. [...]
  9. [...]
  10. Пусть е быть г «s ENDINDEX стоимость.
  11. Если глобальная является true,
    1. Вызвать метод [[Put]] внутренний метод R с аргументами "lastIndex", е и true.
  12. [...]

Поэтому, чтобы избежать этого, вы можете

  • Избегайте использования глобального флага g

    Таким образом, на этапе 7 , i будет 0 вместо lastIndex.

  • Сброс lastIndex вручную после каждого использования

    Значение lastIndex свойство определяет положение струны в , которая, чтобы начать следующий матч.

    Например,

    var test = /[0-9]/g; 
    test.test('0');  // true 
    test.lastIndex;  // 1 
    test.lastIndex = 0; 
    test.test('1');  // true 
    
  • Использование match или search строковые методы

    match сбрасывает lastIndex в 0, и search игнорирует:

    15.5.4.10 String.protot ype.match (регулярное выражение)

    [...] [Если] глобальная является true, вызовите [[Put]] внутренний метод гх с аргументами "lastIndex" и 0. [... ]

    15.5.4.12 String.prototype.search (регулярное выражение)

    [...] Поиск Значение строку с самого начала для возникновения регулярного выражения годовых ttern rx. [...] Объекты lastIndex и global regexp игнорируются при выполнении поиска. [...]

    Например,

    var test = /[0-9]/g; 
    test.test('0');  // true 
    test.lastIndex;  // 1 
    '0'.search(test) > -1; // true 
    test.lastIndex;  // 1 (unaltered) 
    !!'0'.match(test);  // true 
    test.lastIndex;  // 0 
    
Смежные вопросы