1、正则表达式:
1. 正则表达式其实就是一种规则,有自己特殊的应用,其作用就是针对字符串进行操作
2. 正则:就是用于操作字符串的一种规则,其中这些规则使用了一些字符表示
2、预定义字符类
. 点 表示任何字符(与行结束符可能匹配也可能不匹配)
\d 数字:[0-9]
\D 非数字: [^0-9]
\s 空白字符:[ \t \n \x0B \f \r]
\S 非空白字符:[^\s]
\w 单词字符:[a-z A-Z _ 0-9]
\W 非单词字符:[^\w]
注意:任何预定义字符在没有加上数量词之前,都只能匹配一个字符而已。
2.1 预定义字符案例
// . 表示任意字符,匹配任意字符都返回true
System.out.println(". 匹配任意字符?" + ("a".matches(".")));
System.out.println();
// \d 表示数字0-9其中一位,匹配0-9返回true,其他返回false
System.out.println("\\d 匹配任意数字[0-9]?" + ("3".matches("\\d")));
System.out.println();
// \D 表示非数字,即非\d [^0-9],只要不是数字0-9即返回true
System.out.println("\\D 匹配任意非数字字符:?" + ("a".matches("\\D")));
System.out.println();
// \s 表示空白字符 [ \t \n \x0B \f \r ],匹配这些空调字符返回true,其他返回false
System.out.println("\\s 匹配任意空白字符?" + ("\t".matches("\\s")));
System.out.println();
// \S 表示非空表字符 [^\s]
System.out.println("\\S 匹配任意非空白字符?" + ("s".matches("\\S")));
System.out.println();
// \w 表示单词字符:[a-zA-Z_0-9],匹配大小写a-z,数字0-9,下划线_,返回true,其他返回false
System.out.println("\\w 匹配任意单词字符?" + ("_".matches("\\w")));
System.out.println();
// \W 表示非单词字符:[^\w]
System.out.println("\\W 匹配任意非单词字符:?" + ("#".matches("\\W")));
执行结果:
. 匹配任意字符?true
\d 匹配任意数字:(匹配一位数字[0-9])?true
\D 匹配任意非数字字符:?true
\s 匹配任意空白字符?true
\S 匹配任意非空白字符?true
\w 匹配任意单词字符?true
\W 匹配任意非单词字符:?true
3、Greedy 数量词
X ? 一次或一次也没有(?表示 最多出现一次X字符) X * 零次或多次(* 表示 任意次) X + 一次或多次(+ 表示 最少出现一次X字符) X {n} 恰好n次(出现n次X字符) X {n,} 至少n次(最少出现n次X字符) X {n,m} 至少n次,最多m次(出现n<=x<=m 次X字符)
3.1 Greedy 数量词案例:
// X ?: 问号 表示一次或一次也没有(最多出现一次X字符)
System.out.println("? 表示 最多一次(0次)?" + ("".matches("\\w?")));// true
System.out.println("? 表示 最多一次(1次)?" + ("a".matches("\\w?")));// true
System.out.println("? 表示 最多一次(2次)?" + ("aa".matches("\\w?")));// false
System.out.println();
// X *: 星号 表示零次或多次(出现任意次数的X字符)
System.out.println("*表示出现 任意次(0次)?" + ("".matches("\\d*")));// true
System.out.println("*表示出现 任意次(1次)?" + ("1".matches("\\d*")));// true
System.out.println("*表示出现 任意次(2次)?" + ("11".matches("\\d*")));// true
System.out.println();
// X +: 加号表示一次或多次(最少出现一次)
System.out.println("+表示出现1次或多次(0次)?" + ("".matches("\\d+")));// false
System.out.println("+表示出现1次或多次(1次)?" + ("1".matches("\\d+")));// true
System.out.println("+表示出现1次或多次(2次)?" + ("11".matches("\\d+")));// true
System.out.println();
// X {n}: {n}大括号里写次数,表示正好出现n次X字符
System.out.println("{2} 表示恰好出现2次(1次)?" + "1".matches("\\d{2}"));// false
System.out.println("{2} 表示恰好出现2次(2次)?" + "11".matches("\\d{2}"));// true
System.out.println("{2} 表示恰好出现2次(3次)?" + "111".matches("\\d{2}"));// false
System.out.println();
// X {n,}: 表示至少出现n次X字符,n次或以上为true,n次以下为false
System.out.println("{2,} 表示恰好出现2次(1次)?" + "1".matches("\\d{2,}"));// false
System.out.println("{2,} 表示恰好出现2次(2次)?" + "11".matches("\\d{2,}"));// true
System.out.println("{2,} 表示恰好出现2次(3次)?" + "111".matches("\\d{2,}"));// true
System.out.println();
// X {n,m}: 表示最少出现n次,最多出现m次
System.out.println("{2,4} 表示至少出现2次,最多出现4次(1次)?" + ("1".matches("\\d{2,4}")));// false
System.out.println("{2,4} 表示至少出现2次,最多出现4次(2次)?" + ("11".matches("\\d{2,4}")));// true
System.out.println("{2,4} 表示至少出现2次,最多出现4次(3次)?" + ("122".matches("\\d{2,4}")));// true
System.out.println("{2,4} 表示至少出现2次,最多出现4次(4次)?" + ("1333".matches("\\d{2,4}")));// true
System.out.println("{2,4} 表示至少出现2次,最多出现4次(5次)?" + ("14444".matches("\\d{2,4}")));// false
System.out.println();
执行结果:
? 表示 最多一次(0次)?true
? 表示 最多一次(1次)?true
? 表示 最多一次(2次)?false
* 表示出现 任意次(0次)?true
* 表示出现 任意次(1次)?true
* 表示出现 任意次(2次)?true
+ 表示出现1次或多次(0次)?false
+ 表示出现1次或多次(1次)?true
+ 表示出现1次或多次(2次)?true
{2} 表示恰好出现2次(1次)?false
{2} 表示恰好出现2次(2次)?true
{2} 表示恰好出现2次(3次)?false
{2,} 表示恰好出现2次(1次)?false
{2,} 表示恰好出现2次(2次)?true
{2,} 表示恰好出现2次(3次)?true
{2,4} 表示至少出现2次,最多出现4次(1次)?false
{2,4} 表示至少出现2次,最多出现4次(2次)?true
{2,4} 表示至少出现2次,最多出现4次(3次)?true
{2,4} 表示至少出现2次,最多出现4次(4次)?true
{2,4} 表示至少出现2次,最多出现4次(5次)?false
4、范围表示
[abc]: 表示 a、b 或 c [^abc]: 表示 任何字符,除了 a、b 或 c [a-zA-Z]: 表示 a-z 或 A-Z,两头的字母包括在内 [a-d[m-p]]: 表示 a-d 或者 m-p 的并集 [bcd&&[def]]: 表示bcd与def的交集 [a-z&&[^bc]]: 表示 a-z,除了 b 和 c:[a或者d-z] [a-z&&[^m-p]]: 表示 a-z和 【a-z 除去m-p】的交集,即 a-l 或者 q-z
4.1 范围表示 案例
// [abc]:表示匹配a、b 或 c其中的一个字符(简单类)
System.out.println("[abc]表示匹配a或b或c为true(a)?" + ("a".matches("[abc]")));//true
System.out.println("[abc]表示匹配a或b或c为true(e)?" + ("e".matches("[abc]")));//false
System.out.println();
// [^abc]:表示匹配任何字符(1个),除了 a、b 或 c(否定)
System.out.println("[^abc]表示匹配除abc之外的任意一个字符(a)?" +
("a".matches("[^abc]")));//false
System.out.println("[^abc]表示匹配除abc之外的任意一个字符(3)?" +
("3".matches("[^abc]")));//true
System.out.println();
//[a-zA-Z]:表示匹配 a到z 或 A到Z 中的任意一个字符,两头的字母包括在内(范围)
System.out.println("[a-zA-Z]表示匹配a-z和A-Z之中的任意一个字符(F)?" + ("F".matches("[a-zA-Z]")));//true
System.out.println("[a-zA-Z]表示匹配a-z和A-Z之中的任意一个字符(f)?" + ("f".matches("[a-zA-Z]")));//true
System.out.println("[a-zA-Z]表示匹配a-z和A-Z之中的任意一个字符(3)?" + ("3".matches("[a-zA-Z]")));//false
System.out.println();
//[a-d[m-p]]:表示 a到d 或 m到p中的任意一个字符(并集)
System.out.println("[a-d[m-p]]表示匹配a-d或m-p之中的任意一个字符(B)?" + ("B".matches("[a-d[m-p]]")));//false
System.out.println("[a-d[m-p]]表示匹配a-d或m-p之中的任意一个字符(b)?" + ("b".matches("[a-d[m-p]]")));//true
System.out.println("[a-d[m-p]]表示匹配a-d或m-p之中的任意一个字符(m)?" + ("m".matches("[a-d[m-p]]")));//true
System.out.println();
// [bcd&&[def]]: 表示bcd和def的交集,结果是字符d
System.out.println("[bcd&&[def]]表示abcd和def的交集(即d)(d)?" +
("d".matches("[bcd&&[def]]")));// true
System.out.println("[bcd&&[def]]表示abcd和def的交集(即d)(e)?" +
("e".matches("[bcd&&[def]]")));// false
System.out.println("[bcd&&[def]]表示abcd和def的交集(即d)(f)?" +
("f".matches("[bcd&&[def]]")));// false
System.out.println();
// [a-z&&[^bc]] 表示a到z 和 【a-z除了b和c】的交集,结果是a或d-z中的一个字符
System.out.println("[a-z&&[^bc]]表示a到z 和 【a-z除了b和c】的交集(a)?" + "a".matches("[a-z&&[^bc]]"));// true
System.out.println("[a-z&&[^bc]]表示a到z 和 【a-z除了b和c】的交集(b)?" + "b".matches("[a-z&&[^bc]]"));// false
System.out.println("[a-z&&[^bc]]表示a到z 和 【a-z除了b和c】的交集(z)?" + "z".matches("[a-z&&[^bc]]"));// true
System.out.println();
// [a-z&&[^m-p]]:表示 a-z 与【a-z减去m-p】的交集,结果是a-l和q-z中的一个字符
System.out.println("[a-z&&[^m-p]]表示 a-z 与【a-z减去m-p】的交集(a)?" + "a".matches("[a-z&&[^m-p]]"));// true
System.out.println("[a-z&&[^m-p]]表示 a-z 与【a-z减去m-p】的交集(m)?" + "m".matches("[a-z&&[^m-p]]"));// false
System.out.println("[a-z&&[^m-p]]表示 a-z 与【a-z减去m-p】的交集(z)?" + "z".matches("[a-z&&[^m-p]]"));// true
System.out.println();
执行结果:
[abc]表示匹配a或b或c为true(a)?true
[abc]表示匹配a或b或c为true(e)?false
[^abc]表示匹配除abc之外的任意一个字符(a)?false
[^abc]表示匹配除abc之外的任意一个字符(3)?true
[a-zA-Z]表示匹配a-z和A-Z之中的任意一个字符(F)?true
[a-zA-Z]表示匹配a-z和A-Z之中的任意一个字符(f)?true
[a-zA-Z]表示匹配a-z和A-Z之中的任意一个字符(3)?false
[a-d[m-p]]表示匹配a-d或m-p之中的任意一个字符(B)?false
[a-d[m-p]]表示匹配a-d或m-p之中的任意一个字符(b)?true
[a-d[m-p]]表示匹配a-d或m-p之中的任意一个字符(m)?true
[bcd&&[def]]表示abcd和def的交集(即d)(d)?true
[bcd&&[def]]表示abcd和def的交集(即d)(e)?false
[bcd&&[def]]表示abcd和def的交集(即d)(f)?false
[a-z&&[^bc]]表示a到z 和 【a-z除了b和c】的交集(a)?true
[a-z&&[^bc]]表示a到z 和 【a-z除了b和c】的交集(b)?false
[a-z&&[^bc]]表示a到z 和 【a-z除了b和c】的交集(z)?true
[a-z&&[^m-p]]表示 a-z 与【a-z减去m-p】的交集(a)?true
[a-z&&[^m-p]]表示 a-z 与【a-z减去m-p】的交集(m)?false
[a-z&&[^m-p]]表示 a-z 与【a-z减去m-p】的交集(z)?true
注意:正则表达式中 大括号{ n }表示次数,中括号[a-z]表示范围。
注意:范围词里边,不管内容有多长,没有数量词的配合,只能匹配其中的一个字符。
5、分组()
为了提高规则的复用,用()小括号来对正则表达式的字节进行分组,每个括号都有一个编号,编号从1开始。可以通过编号来完成对该规则的调用。注意:需要对编号规则进行转义,\\1就表示获取第一组规则,\\2代表获取第二组规则,以此类推。
5.1 案例
// 需求:将手机号的中间四位使用*号代替
// 第一步,找到手机号,将手机号分组成三部分,前三位是第一组,中间四位是第二组,最后四位是第三组
// 第二步,将手机号的中间4位用 * 号代替
public static void testReplace() {
String str = "联系我:13567012119联系我:13567012119联系我:13567012119联系我:13567012119联系我:13567012119联系我:13567012119";
// 使用小括号将正则表达式分为3组。
String reg = "(1[34578][0-9])(\\d{4})(\\d{4})";
// // $1表示匹配到的第1组子表达式,$3表示第三组子表达式。$1,$2,$3这种格式直接写在正则表达式中是错误的,它只是起到一个占位的作用。
String s = str.replaceAll(reg, "$1****$3");
System.out.println("替换后的帖子是:" + s);
}
执行结果:
替换后的帖子是:联系我:135****2119联系我:135****2119联系我:135****2119联系我:135****2119联系我:135****2119联系我:135****2119
6.边界匹配器
^ | 行的开头 |
$ | 行的结尾 |
\b | 单词边界 |
\B | 非单词边界 |
\A | 输入的开头 |
\G | 上一个匹配的结尾 |
\Z | 输入的结尾,仅用于最后的结束符(如果有的话) |
\z | 输入的结尾 |
7.正则表达式的四种常见应用
1. 匹配
常用方法 matches(reg)
2. 切割
常用方法 split(reg)
3. 替换
常用方法 replace(reg,replacement) 、replaceAll(reg,replaement)
4. 查找
此时需要使用正则表达式对象
7.1 正则表达式的常见应用案例:
public static void main(String[] args) {
// 1.匹配应用
System.out.println("使用正则表达式匹配手机号:" + matchesPhone("13933395149"));
System.out.println("使用正则表达式匹配固话:" + matchesTel("0315-7421005"));
System.out.println();
// 切割应用
System.out.println("使用正则表达式按照空格进行切割:" + Arrays.toString(testSplit1(" 今 天 大 家 玩 的 开 心 ")));
System.out.println("使用正则表达式按照重叠词进行切割:" + Arrays.toString(testSplit2("大家家家家家玩玩的的的的开心心心!!!")));
// 替换应用
testReplace1();
testReplace2();
// 查找应用
getWord();;
}
// 需求:正则表达式匹配手机号,第一位是1,第二位345789,后边全是数字,一共11位
public static String matchesPhone(String phone) {
String reg = "1[34578]\\d{9}";
return phone.matches(reg) ? "合法手机号" : "非法手机号";
}
// 需求:正则表达式匹配固话 区号首位是0,长度3-4位,主机号,首位不能是0,长度7-8位
public static String matchesTel(String tel) {
String reg = "0\\d{2,3}-[1-9]\\d{6,7}";
return tel.matches(reg) ? "合法固话" : "非法固话";
}
// 按照空格进行切割
public static String[] testSplit1(String string) {
return string.split(" +");
}
// 根据重叠词进行切割
public static String[] testSplit2(String string) {
// 如果正则的内容需要被复用,那么需要对正则的内容进行分组,分组的目的是 为了提高正则的复用性。
return string.split("(.)\\1+(.)\\2+");
}
// 需求:将字符串中的手机号中间4位替换成****号
public static void testReplace1() {
String str = "联系我:13567012119联系我:13567012119联系我:13567012119联系我:13567012119联系我:13567012119联系我:13567012119";
String reg = "(1[34578][0-9])(\\d{4})(\\d{4})";
// $1表示匹配到的第1组子表达式,$3表示第三组子表达式。$1,$2,$3这种格式直接写在正则表达式中是错误的,它只是起到一个占位的作用
String s = str.replaceAll(reg, "$1****$3");
System.out.println("替换后的帖子是:" + s);
}
// 需求:"我我....我...我.要...要要...要学....学学..学.编..编编.编.程.程.程..程",将字符串还原成 "我要学编程"。
// 分析:第一步:先将所有点去掉。 第二步将所有重叠字进行切割并保留一个
public static void testReplace2() {
String str = "我我....我...我.要...要要...要学....学学..学.编..编编.编.程.程.程..程";
// 将所有.去掉
str = str.replaceAll("\\.+", "");
System.out.println(str);
// 将重叠字进行叠词处理,并保留一个
str = str.replaceAll("(.)\\1+", "$1");
System.out.println(str);
}
8、通用的正则表达式
手机号: ^1(3[\\d]|4[579]|5[0-3[5-9]]|6[2[5-7]]|7[1-3[5-8]]|8[0-9]|9[0-3[5-9]])\\d{8}$
邮箱: ^[0-9a-zA-Z]+([-\\w])+@([\\w]+\\.)+[a-z]{2,}$
或
^[a-z0-9A-Z]+[-|a-z0-9A-Z._]+@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-z]{2,}$
手机号和邮箱的通用表达式有多重写法,可以根据自己的习惯编写,比如将 [0-9] 写成 [\\d],或者将 [0-3[5-9]] 写成 [0-9&&[^4]],找到规律就好。勤加练习,应付工作上的一般状况还是很轻松的。
9、正则对象
1、查找需要使用的对象:
Pattern:正则对象
Matcher:匹配器
2、正则表达式的编译表示形式。
指定为字符串的正则表达式必须首先被编译为此类的实例。然后,可将得到的模式用于创建 Matcher 对象,
依照正则表达式,该对象可以与任意字符序列匹配。执行匹配所涉及的所有状态都驻留在匹配器中,所以多个匹配器可以共享同一模式。
因此,典型的调用顺序是
Pattern p = Pattern.compile("a*b");
Matcher m = p.matcher("aaaaab");
boolean b = m.matches();
3、匹配器要使用的方法
find():通知匹配器去匹配字符串,查找符合规则的子串。如果能查找到符合规则的子字符串,返回true,否则返回false
group():获取符合规则的子串
注意:使用group方法之前,一定要使用find方法去查找符合规则的字符串,否则报错。
9.1 案例
使用正则对象查找符合正则表达式规则的内容:需求 在字符串中查找由三个字母组成的单词
// 需求:在字符串中获取由三个字母组成的单词
public static void getWord() {
String str = "da jia hao , ming tian bu fang jia , xie xie !";
String reg = "\\b[a-zA-Z]{3}\\b";
// 首先要把字符串的正则编译成Pattern正则对象,\b表示单词的边界
Pattern pattern = Pattern.compile(reg);
// 使用正则对象匹配字符串,用于产生一个Matcher 匹配器对象
Matcher matcher = pattern.matcher(str);
// matcher.find():判断字符串中是否存在符合正则表达式的内容
// matcher.group():获取符合正则规则的字符串内容
while (matcher.find()) {
System.out.println(matcher.group());
}
}