Javascript正则表达式返回true,然后返回false,然后返回true等等...

150
我在表单验证方面遇到了一个奇怪的问题。表单上有一个“检查用户名”按钮,它旁边有一个输入框,输入框默认值是用户名,例如“betamax”。当我按下“检查用户名”按钮时,它会通过正则表达式并将用户名发送到服务器。服务器按预期行事,并返回“2”以告诉javascript他们正在提交自己的用户名。
然后,当我再次点击按钮时,正则表达式失败了。显然没有发送任何东西到服务器,因为正则表达式已失败。如果我再次按下按钮,则正则表达式通过,然后用户名被发送到服务器。
我真的无法弄清楚是什么原因导致它这样做!对我来说毫无意义!
编辑:我已在Firefox和Chrome (mac)中测试了此问题。
这是我的代码:
$j("#username-search").click(checkUserName);

function checkUserName() {
    var userName = $j("#username").val();


    var invalidUserMsg = 'Invalid username (a-zA-Z0-9 _ - and not - or _ at beginning or end of string)';
    var filter = /^[^-_]([a-z0-9-_]{4,20})[^-_]$/gi;
    if (filter.test(userName)) {
        console.log("Pass")
        $j.post(
        "/account/profile/username_check/", 
        { q: userName }, 
        function(data){
            if(data == 0) {
                $j("#username-search-results").html("Error searching for username. Try again?");
            }
            else if(data == 5) {
                $j("#username-search-results").html(invalidUserMsg);
            }
            else if(data == 4) {
                $j("#username-search-results").html("Username too short or too long.");
            }
            else if(data == 2) {
                $j("#username-search-results").html("This is already your username.");
            }
            else if(data == 3) {
                $j("#username-search-results").html("This username is taken.");
            }
            else if(data == 1){
                $j("#username-search-results").html("This username is available!");
            }
        });
    } else {
        console.log("fail")
        $j("#username-search-results").html(invalidUserMsg);
    }

    return false;

}

HTML代码:

<input name="username" id="username" value="{{ user.username }}" />
<input type="button" value="Is it taken?" id="username-search">
<span id="username-search-results"></span>
2个回答

301
/^[^-_]([a-z0-9-_]{4,20})[^-_]$/gi;
您正在使用一个全局正则表达式g。在JavaScript中,全局正则表达式有状态:第一次调用(使用exectest等函数),您将获得给定字符串中的第一个匹配项。再次调用它们,您将获得下一个匹配项,依此类推,直到您没有匹配项并且它重置为下一个字符串的开头。您还可以编写regex.lastIndex = 0来重置此状态。
(当然,这是一种绝对可怕的设计,保证会引起混淆并导致奇怪的错误。欢迎来到JavaScript!)
您可以省略RegExp中的g,因为您仅测试一个匹配项。
此外,我认为您不想在前后使用[^-_]。那将允许每个端点有任何字符,例如*plop! 将是有效的。您可能在考虑前瞻/后顾断言,但它们在JavaScript中不可用。 (好吧,应该提供前瞻,但它在IE中被破坏了)。我建议使用以下代码:
/^[a-z0-9][a-z0-9_-]{2,18}[a-z0-9]$/i

11
就这样了。我通常出于习惯会包含/g,但我想我以后不会这样做了!谢谢! - betamax
我猜如果你使用捕获组创建全局正则表达式并在其上调用“test”,那么这是一种有点疯狂的请求 - 你想测试哪个捕获组?并不是为了辩解JavaScript,他们选择了一个稍微疯狂的问题的最疯狂的解决方案。 - Jon z
这里说明了https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test#using_test_on_a_regex_with_the_global_flag,感谢@bobince,我之前不知道 :) - Ricardo Martínez
如果这是你正在寻找的答案,那么现在是学习正则表达式的时候了。 - GHOST-34
来这里是为了阅读这篇文章。 - androidavid

2
[a-z0-9-_]

这是错误的,最后一个 - 必须在开头或结尾。
[a-z0-9_-]

无论是否会导致此问题,我都不知道。
附加说明:
第一个和最后一个字符可以是任何不是“-”或“_”的字符,而不仅限于“a-z0-9”。
“a-z0-9”不包括大写字符。 您需要使用“a-zA-Z0-9”来进行匹配。 在大多数正则表达式引擎中,“a-zA-Z0-9_”可以缩写为“\w”。 我没有在JavaScript中尝试过。

谢谢你的提示。为什么顺序很重要?不幸的是,这并没有解决我遇到的问题。我刚在Chrome中测试了一下(之前使用的是Firefox),但结果还是一样的。 - betamax
“-”是组中的特殊字符...正如您所看到的,因为您将其用于“a-z”。由于这一点,它被定义为仅作为RegEx的第一个或最后一个字符的文字“-”。话虽如此,您可能还需要在[^-_]中进行切换(改为[^_-])。 - Powerlord
糟糕,我刚刚注意到在我的答案中我写成了/w而不是\w。现在已经修复了。 - Powerlord
我在正则表达式的末尾使用了'i'标志,使其不区分大小写。我注意到正则表达式中的另一个缺陷是它接受除了-或_之外的任何字符作为字符串开头(例如,betamax£将是有效的)。因此,在考虑到这一点和bobince提到的修复措施后,最终的正则表达式是 /^[a-z0-9]([a-z0-9_-]{4,20})[a-z0-9]$/i - betamax
1
你也可以使用 \- 在字符组中插入一个字面上的连字符。虽然按照正则表达式的标准,这种方法可能更易读一些!@betamax:是的,我刚刚发现并添加了它! :-) - bobince

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接