正则表达式之密码验证
对于门户网站,用户注册或修改密码时,需要有正则表达式验证密码,根据安全级别不同,网站会设置不同基本的密码正则表达式。
而此文主要通过一个实例,来讲解密码正则表达式中使用的特殊正则语法,如?! 、?= 等(Java代码验证)。
密码强度要求
- 至少包含一个数字,一个字母,一个特殊字符
- 密码长度在8~18之间
特殊正则语法
- Java 8 API中Pattern类对特殊正则语法的描述
- 正则字符详细说明
字符 | 说明 |
---|---|
* | 零次或多次匹配前面的字符或子表达式。例如,zo* 匹配"z"和"zoo"。* 等效于 {0,}。 |
+ | 一次或多次匹配前面的字符或子表达式。例如,"zo+"与"zo"和"zoo"匹配,但与"z"不匹配。+ 等效于 {1,}。 |
? | 零次或一次匹配前面的字符或子表达式。例如,"do(es)?"匹配"do"或"does"中的"do"。? 等效于 {0,1}。 |
. | 匹配除"\r\n"之外的任何单个字符。若要匹配包括"\r\n"在内的任意字符,请使用诸如"[\s\S]"之类的模式。 |
(?=pattern) | 执行正向预测先行搜索的子表达式,该表达式匹配处于匹配 pattern 的字符串的起始点的字符串。它是一个非捕获匹配,即不能捕获供以后使用的匹配。例如,'Windows (?=95 |
(?!pattern) | 执行反向预测先行搜索的子表达式,该表达式匹配不处于匹配 pattern 的字符串的起始点的搜索字符串。它是一个非捕获匹配,即不能捕获供以后使用的匹配。例如,'Windows (?!95 |
密码正则表达式
- 正向断言: regex =
^(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[!@#$_&*+-])[0-9a-zA-Z!@#$_&*+-]{8,18}$
解释:根据上面的正则字符说明,先分析(?=.*[0-9])
, 其中?=pattern01
是正向先行搜索子表达,不获取匹配,其实可以理解为断言匹配的string能够用pattern01
匹配到子表达,如果断言成功,则就用剩下剩余的regex去匹配此string,否则regex即匹配不成功;
而.*[0-9]
表示匹配以数字结尾的字符串(即整个待匹配的字符串包含数字),所以(?=.*[0-9])
表示为断言字符串包含数字,(?=.*[a-zA-Z])
断言字符串包含字母,(?=.*[!@#$_&*+-])
断言字符创包含特殊字符;若这三个断言成功,就限定了string至少含有数字、字母、特殊字符;
而最后的[0-9a-zA-Z!@#$_&*+-]就限定了只能包含数字、字母、特殊字符。 - 反向断言: regex =
^(?![a-zA-Z0-9]+$)(?![a-zA-Z!@#$%^_&*]+$)(?![0-9!@#$%^_&*]+$)[a-zA-Z0-9!@#$%^_&*]{8,18}$
解释:(?![a-zA-Z0-9]+$)
表示不能只包含数字和字母,同理,三个反向断言也可以限定至少包含一个数字、字母、特殊字符
代码测试
public class HelloWorld {
public static void main(String []args) {
// testRegexPositive();
testRegexNegative();
}
public static void testRegexPositive() {
System.out.println("=====testRegexPositive====");
String reg = "^(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[!@#$_&*+-])[0-9a-zA-Z!@#$_&*+-]{8,18}$";
Pattern pattern = Pattern.compile(reg);
Scanner sc = new Scanner(System.in);
while( sc.hasNext() ) {
String str = sc.nextLine();
Matcher matcher = pattern.matcher(str);
if ( matcher.matches() ) {
System.out.println( str + " matched! length = " + String.valueOf(str.length()) );
} else {
System.out.println( str + " not matched! length = " + String.valueOf(str.length()) );
}
}
}
public static void testRegexNegative() {
System.out.println("=====testNegative====");
String reg = "^(?![a-zA-Z0-9]+$)(?![a-zA-Z!@#$%^_&*]+$)(?![0-9!@#$%^_&*]+$)[a-zA-Z0-9!@#$%^_&*]{8,18}$";
Pattern pattern = Pattern.compile(reg);
Scanner sc = new Scanner(System.in);
while( sc.hasNext() ) {
String str = sc.nextLine();
Matcher matcher = pattern.matcher(str);
if ( matcher.matches() ) {
System.out.println( str + " matched! length = " + String.valueOf(str.length()) );
} else {
System.out.println( str + " not matched! length = " + String.valueOf(str.length()) );
}
}
}
}
- 正向测试结果
=====testRegexPositive====
1234asdf
1234asdf not matched! length = 8
asdf@w1
asdf@w1 not matched! length = 7
asdf@w12
asdf@w12 matched! length = 8
- 反向测试结果
=====testNegative====
1234asdf
1234asdf not matched! length = 8
1234asd
1234asd not matched! length = 7
1234asd#
1234asd# matched! length = 8