【问题标题】:Why is my RegExp construction not accepted by JavaScript?为什么 JavaScript 不接受我的 RegExp 构造?
【发布时间】:2009-03-25 16:05:00
【问题描述】:

我正在使用 RegExp 来验证 ASP.NET 网页上的一些用户输入。它旨在强制构建密码(即长度在 8 到 20 之间,至少一个大写字符,至少一个小写字符,至少一个数字,至少一个字符 #@!$% 并且没有用由字母 L 或 O(大写或小写)或数字 0 和 1 组成。这个 RegExp 在我的测试器(Expresso)和我的 C# 代码中运行良好。

看起来是这样的:

(?-i)^(?=.{8,20})(?=.*[2-9])(?=.*[a-hj-km-np-z])(?=.*[A-HJ-KM-NP-Z])
(?=.*[#@!$%])[2-9a-hj-km-np-zA-HJ-KM-NP-Z#@!$%]*$

(为格式化添加换行符)

但是,当我在 IE6 或 IE7 中运行代码时(没有尝试过其他浏览器,因为这是一个内部应用程序,我们是 Microsoft 商店),我收到一个运行时错误,提示“常规语法错误”表达'。就是这样 - 除了行号之外,错误消息中没有更多信息。

JavaScript 不喜欢这个的原因是什么?

【问题讨论】:

    标签: javascript regex


    【解决方案1】:

    嗯,在 Javascript 中定义正则表达式有两种方法:

    一个。通过 Regexp 对象构造函数:

    var re = new RegExp("pattern","flags");
    re.test(myTestString);
    

    b.使用字符串文字:

    var re = /pattern/flags;
    

    您还应该注意,JS 不支持正则表达式的某些原则。有关 JS 中不支持的功能的非全面列表,请查看regular-expressions.info 站点。

    具体来说,您似乎在表达式上设置了一些标志(例如,不区分大小写的标志)。我建议您使用/i 标志(如上面的语法所示)而不是使用(?-i)

    这将使您的正则表达式如下(似乎支持正预测):

    /^(?=.{8,20})(?=.*[2-9])(?=.*[a-hj-km-np-z])(?=.*[A-HJ-KM-NP-Z])(?=.*[#@!$%])[2-9a-hj-km-np-zA-HJ-KM-NP-Z#@!$%]*$/i;
    

    有关该主题的非常好的文章,请查看Regular Expressions in JavaScript

    编辑(在霍华德评论之后)


    如果您只是将此 Regex 模式分配给 RegularExpressionValidator 控件,那么您将无法设置 Regex 选项(例如忽略大小写)。此外,您将无法使用 Javascript 支持的 Regex 文字语法。因此,剩下的唯一选择是让您的模式本质上不区分大小写。例如,[a-h] 必须写为[A-Ha-h]。很抱歉,这会使您的正则表达式变得冗长。

    Here is a solution 这个问题,虽然我不能保证它的合法性。想到的其他一些选项可能是完全关闭客户端验证并专门在服务器上验证。这将使您能够访问由System.Text.RegularExpressions.Regex 对象实现的完整正则表达式风格。或者,使用 CustomValidator 并创建您自己的 JS 函数,该函数使用我(和其他人)建议的模式应用正则表达式匹配。

    【讨论】:

    • 感谢 :) 我自己没有编写 Javascript,我使用的是 VS2008,它从我使用的验证控件生成 Javascript。我所做的就是告诉它要使用的正则表达式。我将尝试 /i 建议。 // 字符是否告诉 Javascript 忽略字符串中潜在的转义字符?
    • 编辑了我的帖子以包含有关 RegexValidator 的信息。希望这会有所帮助。
    • 感谢您的帮助 - 非常有建设性且非常有用:)
    【解决方案2】:

    我不熟悉 C# 的正则表达式语法,但这是(开头)

    (?-i)
    

    要打开不区分大小写的模式修饰符吗?如果是这样,那是你的问题。 Javascript 不支持在表达式中指定模式修饰符。在 javascript 中有两种方法可以做到这一点

    var re = /pattern/i
    var re = new RegExp('pattern','i');
    

    试一试,你的表情应该会很开心。

    【讨论】:

      【解决方案3】:

      正如 Cerberus 所提到的, (?-i) 在 JavaScript 正则表达式中不受支持。所以,你需要摆脱它并使用 /i。需要记住的是,正则表达式语法没有标准。它在每种语言中都不同,因此在使用 .NET 正则表达式引擎的东西中进行测试并不是对它在 JavaScript 中如何工作的有效测试。相反,请尝试查找有关 JavaScript 正则表达式的参考,例如 this one

      查找 8-20 个字符的匹配也是无效的。这将确保至少有 8 个字符,但它不会将字符串限制为 20 个,因为末尾带有 kleene-closure(* 运算符)的字符类可以匹配提供的尽可能多的字符。您想要的是将末尾的 * 替换为 {8,20},并从头开始删除它。

      var re = /^(?=.*[2-9])(?=.*[a-hj-km-np-z])(?=.*[A-HJ-KM-NP-Z])(?=.*[#@!$%])[2-9a-hj-km-np-zA-HJ-KM-NP-Z#@!$%]{8,20}$/i;
      

      另一方面,我不太确定您为什么要限制密码长度,除非存在硬数据库限制(不应该有,因为您不应该以纯文本形式存储密码在数据库中,而是使用带有盐的安全散列算法将它们散列到固定大小)。如前所述,我认为没有理由对您允许的字符集进行如此严格的限制。我会推荐更多类似的东西:

      var re = /^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[#@!$%])[a-zA-Z0-9#@!$%]{8,}$/i;
      

      另外,您为什么要禁止密码中的 1、0、L 和 O(看起来您也试图禁止 I,但您忘了提及)?这将使人们很难构建好的密码,并且由于您在输入密码时永远不会看到密码,因此没有理由担心看起来令人困惑的相似字母。如果你想要一个更宽松的正则表达式:

      var re = /^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[#@!$%]).{8,}$/i;
      

      【讨论】:

      • 第 4 段很有用 - 谢谢。其余的与我的问题无关 - 保持重点,少浪费一点电......
      • 对不起,当我测试我试图给出的正则表达式作为答案时,我一直不小心使用了字母 I、L 和 O,这意味着它没有通过某些原因除了我目前正在寻找的东西。
      【解决方案4】:

      您是否将正则表达式包含在 // 字符中?

      var regexp = /[]/;
      return regexp.test();
      

      【讨论】:

      • 嗨,我不是自己编写 Javascript,我使用 Visual Studio 2008,它会从我正在使用的验证控件生成 Javascript。这些字符是否告诉 Javascript 忽略字符串中潜在的转义字符?
      • / 字符表示正则表达式的开始和结束。里面的 [] 表示你的正则表达式会去哪里。
      【解决方案5】:

      (?-i)

      JS Regexp 中不存在。标志可以指定为“new RegExp('pattern', 'i')”,或文字语法“/pattern/i”。

      (?=

      存在于 JS Regexp 的 modern implementations 中,但在 IE 中是危险的 buggy。出于这个原因,在 JS 中应该避免 前瞻断言

      长度在 8 到 20 之间,至少一个大写字符,至少一个小写字符,至少一个数字,至少一个字符 #@!$% 并且不能使用字母 L 或 O(大写或更低)或数字 0 和 1。

      您是否必须在 RegExp 中执行此操作,并且您是否必须将所有条件放在一个 RegExp 中?因为这些条件很容易使用多个正则表达式匹配,甚至是简单的字符串匹配:

      if (
          s.length<8 || s.length>20 ||
          s==s.toLowerCase() || s==s.toUpperCase() ||
          s.indexOf('0')!=-1 || s.indexOf('1')!=-1 ||
          s.toLowerCase().indexOf('l')!=-1 || s.toLowerCase().indexOf('o')!=-1 ||
          (s.indexOf('#')==-1 && s.indexOf('@')==-1 && s.indexOf('!')==-1 && s.indexOf('%')==-1 && s.indexOf('%')==-1)
      )
          alert('Bad password!');
      

      (顺便说一句,如果是针对最终用户的,这些密码规则真的很残酷且无用!)

      【讨论】:

        【解决方案6】:

        我会使用这个正则表达式:

        /(?=[^2-9]*[2-9])(?=[^a-hj-km-np-z]*[a-hj-km-np-z])(?=[^A-HJ-KM-NP-Z]*[A-HJ-KM-NP-Z])(?=[^#@!$%]*[#@!$%])^[2-9a-hj-km-np-zA-HJ-KM-NP-Z#@!$%]{8,}$/
        

        [^a-z]*[a-z] 将确保尽早进行匹配,而不是扩展 @ 987654327@ 并进行回溯。

        【讨论】:

          【解决方案7】:

          (?-i) 应该关闭不区分大小写。似乎每个人都认为您正在尝试打开它,但那是(?i)。无论如何,您不希望它不区分大小写,因为您需要确保同时存在大写和小写字母。由于区分大小写的匹配是默认设置,因此即使在支持内联修饰符的那些风格(如 .NET)中,在正则表达式前面加上 (?-i) 也是没有意义的。

          【讨论】:

            猜你喜欢
            • 2022-12-11
            • 1970-01-01
            • 1970-01-01
            • 2021-11-09
            • 2017-02-20
            • 1970-01-01
            • 2014-03-30
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多