Неожиданная проблема с поведением JavaScript - PullRequest
1 голос
/ 30 июня 2010

Я написал этот метод проверки, но у меня возникли проблемы с ним.

function validate_password(pwd)
{
    var score = 0;

    // Min length is 8
    if (pwd.length<8)
        return false;

    // Is lower present?
    if (/[a-z]/g.test(pwd))
    {
        console.log('a-z test on "'+pwd+'":' + /[a-z]+/g.test(pwd));
        score++;
    }

    // Is upper present?
    if (/[A-Z]/g.test(pwd))
    {
        console.log('A-Z test on: "'+pwd+'":' + /[A-Z]+/g.test(pwd));
        score++;
    }

    // Is digit present?
    if (/\d/g.test(pwd))
    {
        console.log('digit test on: "'+pwd+'":' + /\d/g.test(pwd));
        score++;
    }

    // Is special char present?
    if (/\W/g.test(pwd))
    {
        console.log('spec char test on: "'+pwd+'":' + /\W/g.test(pwd));
        score++;
    }

    if (score>=3)
        return true;
    else
        return false;
}

Это то, что записано в консоли:

>>> validate_password('aaasdfF#3s')
a-z test on "aaasdfF#3s":true
A-Z test on: "aaasdfF#3s":true
digit test on: "aaasdfF#3s":true
spec char test on: "aaasdfF#3s":true
true

>>> validate_password('aaasdfF#3s')
a-z test on "aaasdfF#3s":true
false

С первой попытки он работаеткак и ожидалось, но когда я вызываю метод во второй раз, он не работает должным образом.

Итак, мой вопрос: почему существуют различия между результатами с первой попытки и со второй попытки?

Спасибо!:)

1 Ответ

1 голос
/ 30 июня 2010

См. Документацию MDC по test.

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

. Решение состоит в том, чтобы удалить глобальный или g флаг из вашегорегулярные выражения:

/[a-z]/ вместо /[a-z]/g и т. д.

Рассмотрим простой пример , чтобы понять причину проблемы:

var l = /[a-z]/g;

// initial search starts at the beginning, matches "a" and returns true
l.test("a"); // true
// since the first character matched, lastIndex moves to the next index - 1
l.lastIndex; // 1

// this time we pass a different string to the regex, but unfortunatly it
// starts searching from the lastIndex which is 1. There are no lower case
// letters from this point onwards (only "---"), so return value is false.
l.test("x---"); // false
// Since this search failed, lastIndex wraps around to the beginning, so the 
// next search will work as expected
l.lastIndex; // 0

Для заданного вами значения "aaasdfF#3s" тест [a-z] в нижнем регистре будет успешным 7 раз, так как есть 7 символов нижнего регистра, но не пройден 8-й раз.И снова добиваться успеха с 9 по 15 раз и так далее.Другие тесты будут проходить каждый раз поочередно, так как есть только один символ каждого типа - "F", "#" и "3", и он оборачивается от lastIndex до 0, когда тест не пройден.

Проблема, по-видимому, связана с тем, что состояние сохраняется в этих объектах RegExp между вызовами функций, то есть объект RegExp создается только один раз, а не каждый раз, когда вызывается функция.Этот небольшой тест подтверждает это:

function RegExpStatePersistenceTest() {
    var regex = /[a-z]/g;

    regex.counter = regex.counter || 0;
    regex.counter++;

    console.log("counter:" + regex.counter);
}

RegExpStatePersistenceTest(); // counter: 1
RegExpStatePersistenceTest(); // counter: 2
RegExpStatePersistenceTest(); // counter: 3
RegExpStatePersistenceTest();​ // counter: 4

Если новый объект был явно создан с использованием new RegExp(..), то при каждом вызове функции будет создаваться новый новый объект RegExp,и состояние не будет сохраняться между вызовами.

Также см. why-regexp-with-global-flag-in-javascript-give-неправильный-результаты

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...