正则化菜鸟教程(比较详细)
正则表达式 – 教程 | 菜鸟教程 (runoob.com)
正则化
正则化是一种用来描述、匹配和操作字符串的强大工具。他是代码中尤为重要的一部分,是做比较时常用的手段。下面是一些常见的正则表达式元字符和用法:
符号 | 用法 |
. | 匹配任意单个字符(除了换行符)。 |
* | 匹配前面的元素零次或多次。 |
+ | 匹配前面的元素一次或多次。 |
? | 匹配前面的元素零次或一次。 |
[ ] | 定义一个字符集,匹配其中的任意一个字符。 |
[ ^ ] | 否定的字符集,匹配未列出的任意一个字符。 |
( ) | 标记一个子表达式的开始和结束位置。 |
| | 用于在两个或多个模式之间进行选择。 |
\ | 用来转义特殊字符,使其具有普通字符的含义。 |
常见的正则表达式示例:
.*
:匹配任意长度的字符序列。[0-9]
:匹配任意一个数字。[a-zA-Z]
:匹配任意一个字母(包括大小写)。\d
:匹配任意一个数字,等效于[0-9]
。\w
:匹配任意一个单词字符(字母、数字或下划线),等效于[a-zA-Z0-9_]
。\s
:匹配任意一个空白字符(空格、制表符、换行符等)。
正则化举例
例题:某网站引入了新的密码强度检测功能,以提高用户账户的安全性,用户设置密码时,系统会根据密码的复杂度给予相应的评级。
密码强度法则如下: 弱密码:密码长度大于等于8个字符,至少包含种类: 大写字母,小写字母、数字里的2种;
中等密码:密码长度大于等于8个字符,至少包含种类:大写字母、小写字母、数字里的2种,必须包含特殊字符 (!$@%&*)
强密码: 密码长度大于等于8个字符,且必须包含大写字母、小写字母、数字和特殊字符。 密码不合法:不满足上述条件
现在你需要写一段java程序判断用户输入的密码评级。
输入描述:键盘输入第一行输入用例个数n,接下来的n行每一行输入一个待检测的密码串。
输出描述:输出n行,每一行输出对应密码的评级,弱密码输出weak,中等密码输出medium ,强密码输出strong,不合法输出error。 密码不合法: 不满足上述条件的。
题中,需要我们判断输入密码是否包含有数字、大小写字母以及特殊符号,包含一个或多个。按照这个题的想法,我们首先需要密码大于8字符,其次需要先判断是否有特殊字符,如果没有则判断弱密码规则,如果有则判断时中等还是强密码即可。
下面是代码(代码是自己写的,可能不够完美,也不是最简短的,有更好的可以自己写):
import java.util.Scanner;
public class HHH {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
scanner.nextLine(); // 消耗换行符
for (int i = 0; i < n; i++) {
String password = scanner.nextLine();
String strength;
int count = 0;
if (password.length() < 8) {
strength = "error";
} else if (containF(password)) {
if (containB(password) && containS(password) && containD(password)) {
strength = "strong";
} else if ((containB(password) && containD(password)) || (containS(password) && containD(password)) || (containS(password) && containB(password))) {
strength = "medium";
} else {
strength = "error";
}
} else if ((containS(password) && containB(password)) || (containS(password) && containD(password)) || (containD(password) && containB(password))) {
strength = "weak";
} else {
strength = "error";
}
System.out.println(strength);
}
}
// 是否包含字符
public static boolean containF(String s) {
return s.matches(".*[!$@%&*].*");
}
// 是否包含大写字母
public static boolean containB(String s) {
return s.matches(".*[A-Z].*");
}
// 是否包含小写字母
public static boolean containS(String s) {
return s.matches(".*[a-z].*");
}
// 是否包含数字
public static boolean containD(String s) {
return s.matches(".*\\d.*");
}
}
这里我每一个都是单独判断的,可以保证字符判断不受符号位置的影响。这句话是什么意思呢?也就是说在使用正则表达式的时候,我们如果写一个很长的正则表达式,则我们字符串上的相匹配字符的顺序必须和表达式顺序相同。可能还是有很多童鞋不太明白什么意思,下面我举个例子具体说明一下。
首先我们写一段正则表达式,并输出:
String a = "AsBB";
String b = "aBcdef";
String c = "A";
String regex = "[A-Z]";
System.out.print(a.matches(regex)+"\t");
System.out.print(b.matches(regex)+"\t");
System.out.print(c.matches(regex)+"\t");
//false false true
上面代码输出结果应该是什么呢?准确答案是false false true。可以看出,正则表达式中一个"[]"只会匹配一个位置,且从第一个位置开始匹配。
如果想让上述a和c变成true,我们就可以加上.*这个特殊的符号,
String a = "AsBB";
String b = "aBcdef";
String c = "A";
String regex = "[A-Z].*";
System.out.print(a.matches(regex)+"\t");
System.out.print(b.matches(regex)+"\t");
System.out.print(c.matches(regex)+"\t");
//true false true
它表示可以匹配它后面的0个或者多个多个,比如:[A-Z].*,表达的意思就是只要字符串中只要第一个是大写字母就算匹配成功。所以b还是false,因为b开头并不是大写字母。
那我们怎么匹配b呢,还是一样,只要我们将条件改成.*[A-Z].*,就表示只要匹配到大写字母,不管前面有什么,也不管后面有什么。简言之就是不管在什么位置的大写字母即可。
String a = "AsBB";
String b = "aBcdef";
String c = "A";
String regex = ".*[A-Z].*";
System.out.print(a.matches(regex)+"\t");
System.out.print(b.matches(regex)+"\t");
System.out.print(c.matches(regex)+"\t");
//true true true
好,现在我们通过.*解决了匹配位置的问题,但是真的解决了吗?回到主题,刚才所说的位置问题还是存在的,如果我想判断一个字符串中既有大写又有小写,该如何写?相信你们很快就有了答案,.*[A-Z].*[a-z].*注:上述写法等同于.*[A-Z].*.*[a-z].*,这样写有问题吗?我们来看下面这个例子
String a = "AsBB";
String b = "aBcdef";
String c = "A";
String d = "aaaaaB";
String regex = ".*[A-Z].*[a-z].*";
System.out.print(a.matches(regex)+"\t");
System.out.print(b.matches(regex)+"\t");
System.out.print(c.matches(regex)+"\t");
System.out.print(d.matches(regex)+"\t");
//true true false false
从例子可以看出,我的c字符串因为只有大写报了false,但是新添加的d为什么也是false,这就是在说的最主要的问题,也就是位置的影响,因为我们的正则化语句的位置关系是大写在前,小写在后,他只能匹配这种位置关系的字符串以至于只有[小写字母,大写字母]这种结构无法被匹配。
当然对于这个问题我们可以写这样的语句:
(.*[A-Z].*[a-z].*)|(.*[a-z].*[A-Z].*)
用括号将两个语句包裹,通过"|"来进行或运算,就可以完成操作,不过这样,如果不是规定的位置明确的关系,远不如用if语句单独进行判断来的更加准确也就是如下:
String d = "aaaaaB";
System.out.println(d.matches(".*[A-Z].*") && d.matches(".*[a-z].*"));
//true