正则表达式接受 4 条规则中的 3 条
Regex to accept 3 out of 4 rules
我似乎无法使正则表达式正确满足以下要求:长度在 8 到 20 之间的字符串必须包含至少 1 个大写字母字符、至少 1 个小写字母字符和至少 1 个数字或至少 1 个特殊字符(或两者)。假设特殊字符仅限于包括@、#、&、~。
我最初是这样写的:
^(?=.*?[A-Z])(?=.*?[a-z])(?=(.*?[0-9])|(.*?[@#&~])).{8,20}$
正如预期的那样,它成功匹配了 5abcdefG、Abc@defghi、5abcdefG~ 等字符串
问题是它允许我提到的 4 个特殊字符以外的字符。因此像 1€abcdefG 和 Abc!defghi 这样的字符串也匹配,但它们不应该匹配。我错过了什么?
重点是你的 .
匹配除换行符以外的任何字符,因此它可以匹配除你的 4 个特殊字符、字母或数字之外的许多字符。
此外,将 OR 条件拆分为 2 个具有先行 ((?=(.*?[0-9])|(.*?[@#&~]))
) 的替代分支是没有意义的。您可以将该条件合并为一个 (?=.*?[0-9@#&~])
。重点是正字符class里面的ranges/chars是"OR'ed",[0-9@#&~]
匹配一个数字,或者@
,或者#
,或 &
,或 ~
.
我建议
^(?=[^A-Z]*[A-Z])(?=[^a-z]*[a-z])(?=[^0-9@#&~]*[0-9@#&~])[A-Za-z0-9@#&~]{8,20}$
您还可以使用注释模式或块来构建动态模式,使模式具有可读性和可维护性:
^ # start of string
(?=[^A-Z]*[A-Z]) # string must have an uppercase letter
(?=[^a-z]*[a-z]) # string must have a lowercase letter
(?=[^0-9@#&~]*[0-9@#&~]) # string must have a digit or defined special char
[A-Za-z0-9@#&~]{8,20} # The string should have 8 to 20 symbols from the defined set
$ # end of string
[A-Za-z0-9@#&~]
将只允许您在此字符中指定的字母、数字和特殊字符 class。
这个正则表达式也符合对比原则(前瞻失败或匹配否定字符更快classes)。
这里的简单答案是不要使用单个正则表达式。这将简化一切:
- 8 到 20 个字符:每种语言都提供了获取字符串长度的标准方法。使用它并检查数字。
- 包含一个大写字母:检查它是否匹配
[A-Z]
。您可能需要修改它以实现国际化。
- 包含一个小写字母:检查它是否匹配
[a-z]
。您可能需要修改它以实现国际化。
- 包含一个数字:检查它是否匹配
[0-9]
.
- 包含特殊字符:检查它是否匹配
[@#&~]
.
- 仅包含允许的字符:使其匹配
^[A-Za-z0-9@#&~]+$
。 (这似乎是一个可疑的要求,特别是如果这是针对密码的。)
在最后两个检查周围会有一些额外的条件,只需要一个,但这没什么大不了的。
最重要的是,没有人能够为此阅读单个正则表达式。您必须记录它所做的一切,每个接触该正则表达式的开发人员要么讨厌您,要么像我在此处描述的那样将其重新实现为多重检查。 停止。严重地。这是 "parse HTML with regex" 级别的糟糕设计。只需使用多次检查。这是最明智的做法。
最重要的是,以后添加新要求会容易得多,如果您 运行 进入无法通过正则表达式检查的内容,则无论如何都必须这样做。
我似乎无法使正则表达式正确满足以下要求:长度在 8 到 20 之间的字符串必须包含至少 1 个大写字母字符、至少 1 个小写字母字符和至少 1 个数字或至少 1 个特殊字符(或两者)。假设特殊字符仅限于包括@、#、&、~。
我最初是这样写的:
^(?=.*?[A-Z])(?=.*?[a-z])(?=(.*?[0-9])|(.*?[@#&~])).{8,20}$
正如预期的那样,它成功匹配了 5abcdefG、Abc@defghi、5abcdefG~ 等字符串
问题是它允许我提到的 4 个特殊字符以外的字符。因此像 1€abcdefG 和 Abc!defghi 这样的字符串也匹配,但它们不应该匹配。我错过了什么?
重点是你的 .
匹配除换行符以外的任何字符,因此它可以匹配除你的 4 个特殊字符、字母或数字之外的许多字符。
此外,将 OR 条件拆分为 2 个具有先行 ((?=(.*?[0-9])|(.*?[@#&~]))
) 的替代分支是没有意义的。您可以将该条件合并为一个 (?=.*?[0-9@#&~])
。重点是正字符class里面的ranges/chars是"OR'ed",[0-9@#&~]
匹配一个数字,或者@
,或者#
,或 &
,或 ~
.
我建议
^(?=[^A-Z]*[A-Z])(?=[^a-z]*[a-z])(?=[^0-9@#&~]*[0-9@#&~])[A-Za-z0-9@#&~]{8,20}$
您还可以使用注释模式或块来构建动态模式,使模式具有可读性和可维护性:
^ # start of string
(?=[^A-Z]*[A-Z]) # string must have an uppercase letter
(?=[^a-z]*[a-z]) # string must have a lowercase letter
(?=[^0-9@#&~]*[0-9@#&~]) # string must have a digit or defined special char
[A-Za-z0-9@#&~]{8,20} # The string should have 8 to 20 symbols from the defined set
$ # end of string
[A-Za-z0-9@#&~]
将只允许您在此字符中指定的字母、数字和特殊字符 class。
这个正则表达式也符合对比原则(前瞻失败或匹配否定字符更快classes)。
这里的简单答案是不要使用单个正则表达式。这将简化一切:
- 8 到 20 个字符:每种语言都提供了获取字符串长度的标准方法。使用它并检查数字。
- 包含一个大写字母:检查它是否匹配
[A-Z]
。您可能需要修改它以实现国际化。 - 包含一个小写字母:检查它是否匹配
[a-z]
。您可能需要修改它以实现国际化。 - 包含一个数字:检查它是否匹配
[0-9]
. - 包含特殊字符:检查它是否匹配
[@#&~]
. - 仅包含允许的字符:使其匹配
^[A-Za-z0-9@#&~]+$
。 (这似乎是一个可疑的要求,特别是如果这是针对密码的。)
在最后两个检查周围会有一些额外的条件,只需要一个,但这没什么大不了的。
最重要的是,没有人能够为此阅读单个正则表达式。您必须记录它所做的一切,每个接触该正则表达式的开发人员要么讨厌您,要么像我在此处描述的那样将其重新实现为多重检查。 停止。严重地。这是 "parse HTML with regex" 级别的糟糕设计。只需使用多次检查。这是最明智的做法。
最重要的是,以后添加新要求会容易得多,如果您 运行 进入无法通过正则表达式检查的内容,则无论如何都必须这样做。