[免责声明,这是一个很长的答案!]
我将从字符限制开始。
您必须使用(?<!\S)
and(?!\S)
指示密码的开头和结尾,并使用\S{8,20}
实际密码:
(?m)(?<!\S)\S{8,20}(?!\S)
正如您可能已经知道的那样(?m)
,它用于多行(^
并$
分别匹配行的开头和结尾,而不是此模式下的字符串)。
(?<!\S)
确保密码前没有非空白字符。
(?!\S)
确保密码后没有非空白字符。
现在我们添加一些限制:
不能以数字或下划线开头:(?![0-9_])
密码开头的负前瞻:
(?m)(?<!\S)(?![0-9_])\S{8,20}(?!\S)
必须包含至少一个数字:(?=\S+[0-9])
密码开头的正向前瞻:
(?m)(?<!\S)(?![0-9_])(?=\S+[0-9])\S{8,20}(?!\S)
必须以相同的字符结尾:您必须捕获倒数第二个字符并使用反向引用。您可以将此\S{8,20}
部分更改\S{6,18}(\S)\1
为:
(?m)(?<!\S)(?![0-9_])(?=\S+[0-9])\S{6,18}(\S)\1(?!\S)
现在应该很好了。
现在到你的正则表达式:
(?m:^([^_|^0-9]{1})
首先,{1} 是多余的,因为如果您删除它,它根本不会改变任何东西。
(?m:^([^_|^0-9])
其次,你有不平衡的括号。不知道那应该是什么,但我猜第一个括号不是故意的。
(?m:^[^_|^0-9])
接下来,字符类[^_|^0-9]
匹配除_
、或范围之外的|
任何字符。我确定密码可以以or开头。元字符在字符类中失去了意义!您可以使用 this:代替,这将变为:^
0-9
|
^
|
[^_0-9]
(?m:^[^_0-9])
可以使用它,但您必须记住这是密码中的第一个字符;因为您要尊重的字符范围为 8 到 20 个,而它刚刚更改为 7,19。唯一剩下的就是它也接受一个空格。您可以在字符类中放置一个来避免这种情况:
(?m:^[^_0-9 ])
好的,现在看起来好多了,下一个:
(?<finalTwo>(?i:\S{1}))(?i:\<finalTwo>)
首先是一个命名的捕获组,好的,具有一个不区分大小写模式的非捕获组(不是很有必要,因为我们在正则表达式中没有任何字母表)并且\S{1}
在该非捕获组内。再一次,这{1}
是多余的。删除它和(?i)
模式,这变成:
(?<finalTwo>\S)(?:\<finalTwo>)
这还不错,如果它匹配最后两个字符,它确实可以工作。
(?=.*\d)
效果很好。您可能想寻找匹配以外的字符0-9
,\d
但如果您不介意,那几乎可以;最好使用\S
而不是在.
这里,以防万一在文本中有两个密码由空格隔开,这可能会使事情不像你想要的那样。
(\S*)
那部分或多或少还可以。只是没有施加限制。
(?=\S*\d)(?m:^[^_0-9 ])(\S*)(?<finalTwo>\S)(?:\<finalTwo>)
好的,现在,请记住(?m:^[^_0-9])
一个字符,(?<finalTwo>\S)(?:\<finalTwo>)
两个字符,总共 3 个。因此施加的限制是:
(?=\S*\d)(?m:^[^_0-9 ])(\S{5,17})(?<finalTwo>\S)(?:\<finalTwo>)
它几乎可以工作,您只需要放置一些东西来防止较长密码的部分匹配。您通常可以使用单词边界\b
,但没有提到任何关于符号的内容,因此假设密码 like$@4*&AUn++
也被允许更安全,这就是单词边界将失败的地方。这就是为什么我建议使用负面环视。