意外的javascript行为问题

时间:2010-06-30 18:58:38

标签: javascript regex

我写了这个验证方法但是遇到了问题。

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 个答案:

答案 0 :(得分:1)

请参阅test上的MDC文档。

  

当您想知道是否在字符串中找到模式时,请使用test方法(类似于String.search方法);有关更多信息(但执行速度较慢),请使用exec方法(类似于String.match方法)。与exec一样,在同一个正则表达式实例上多次调用的测试将超过上一个匹配

解决方案是从正则表达式中删除全局或g标记:

/[a-z]/代替/[a-z]/g,依此类推。

考虑这个simple example,看看问题存在的原因:

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对象只创建一次,而不是每次调用该函数。这个小test证实了这一点:

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-wrong-results