一,正则表达式介绍
正则表达式:校验字符串是否满足一定的规则,用来校验数据格式的合法性
作用:校验字符串是否满足规则,在一段文本中查询满足要求的内容。
-
使用方式(java 中)
String str="123456"; str.matches("正则表达式内容");
使用规则
-
字符类型(只匹配一个字符)
表达式 说明 [abc] 只能是a,b,或c [^abc] 除了a,b,c之外的字符 [a-zA-Z] a到z,或A到Z,包括(范围) [a-d[m-p]] a到d,或m到p [a-z&&[def]] a-z和def的交集:def [a-z&&[^def]] a-z和非def的交集:等同于:[ad-z] [a-z&&[^m-p]] a到z和除了m到p的交集:等同于[a-lq-z] [0-9] 只能为字符0到9 字符类表示比如说:
"abc" 然后 [abc] 这个是对第一个字符 a 进行匹配!后面的 bc 如果也需要匹配就写成 [abc][abc][abc] 这样的形式
-
预定义字符(只匹配一个字符!)
表达式 说明 . 任何字符,除了\n和\r \d 一个数字:相当于[0-9] \D 非数字,相当于:[^0-9] \s 一个空白字符:相当于[\t\n\x0B\f\r] \S 非空白字符 \w 相当于[a-zA-Z_0-9]英文,数字,下划线 \W [^\w]一个非单词字符 注意:在 java 当中 \ 是代表转义字符,如果想写正则表达式需要写 \\d 这种,意思就是把 \d 转义成 \\d
如果不写就代表把字符 d 转义!
-
数量词
表达式 说明 X? ?前面的X出现1次或者0次 X* *前面的X出现0次或者多次 X+ +前面的X出现1次或多次 X{n} X这个出现n次 X{n,} X这个出现n次及以上 x{n,m} X这至少n次但不超过m次 小细节:X 可以是单个字符也可以是一组
ab+ 表示的是第一个字符必须为 a,第二个字符可以是 b 并且可以在后面出现 1 次或多次,这里的 X 代表字符
a(bc)+ 表示的是第一个字符必须为 a,后面进行了分组,这里的 X 是 bc,且 bc 在后面要出现 1 次或多次
-
符号
符号 说明 举例 [] 表示里面的内容只出现一次 [0-9] () 分组 a(bc)+表示,bc这一组至少出现一次,等同于 abcbcbc...(bc至少出现一次) ^ 取反 [^abc] && 两个范围的交集 [a-z&&A-Z] | 写在方括号外面表示并集 x|X . 任意字符 \n回车符号不匹配! \ 转义字符 \\d (?i) 忽略后面字符的大小写 (?i)abc 只忽略b的大小写 a((?i)b)c
二,java使用正则表达式
需要的类:
- Pattern:表示正则表达式类
- Matcher:文本匹配器,作用按照正则表达式的规则去读取字符串,从头开始读取
使用方法:
Pattern p=Pattern.compile("正则表达式");//获取Pattern对象
Matcher m=p.matcher(str);//str里面是文本内容,字符串格式的
//m:文本匹配器
//p:规则
//str:文本
//m要在str中找到符合p规则的小串
m.find();//拿着文本匹配器,从头开始找满足规则的字串,如果有返回true,没有返回false
//找到后会在底层记录小串的起始索引和结束索引+1,之所以+1是因为调用的是substring这个方法剪切的小串!
String s1=m.group();//这个方法会把找到的小串获取出来
//总体来写:
String str="Java自从95年问世以来,经历了很多版本,目前企业中用的最多的是Java8和Java11,因为这两个版本是长期支持版本,下一个长期支持版本是Java17,相信在未来不久Java17也会登上历史的舞台";
Pattern p=Pattern.compile("java\\d{0,2}");
Matcher m=p.matcher(str);
while(m.find()){
String s=m.group();
sout(s);
}
三,带条件的爬取数据
String str="Java自从95年问世以来,经历了很多版本,目前企业中用的最多的是Java8和Java11,因为这两个版本是长期支持版本,下一个长期支持版本是Java17,相信在未来不久Java17也会登上历史的舞台";
//需求1:爬取版本号为8,11,17的java文本,但是只要java文本不要版本号
String regex="Java(?=8|11|17)"//这里是?=
Pattern p=Pattern.compile(regex);
Matcher m=p.matchers(s);
while(m.find()){
System.out.println(m.group());
}
//需求2:爬取版本号为8,11,17的java文本,正确爬取结果为:java8,java11 java 17
String regex="Java(?:8|11|17)"//这里是?:
Pattern p=Pattern.compile(regex);
Matcher m=p.matchers(s);
while(m.find()){
System.out.println(m.group());
}
//需求3:爬取除了版本号为8,11,17的文本
String regex="Java(?!8|11|17)"//这里是!
Pattern p=Pattern.compile(regex);
Matcher m=p.matchers(s);
while(m.find()){
System.out.println(m.group());
}
Java(?=8|11|17) 解释:? 相当于前面的 J 数据 ava,= 代表 Java 后面要跟随 8 或 11 或 17,但是在获取的时候只获取前半部分 Java
Java(?:8|11|17) 解释:? 相当于前面的数据 java,: 代表 Java 后面要跟随 8 或 11 或 17,并且在获取的时候后面要跟随数字 8 或 11 或 17
Java(?!8|11|17) 解释:? 相当于前面的数据 java,! 代表爬取 Java 后面跟随的除了 8 或 11 或 17 的 java 文本
四,贪婪爬取和非贪婪爬取
贪婪爬取:在爬取的时候尽可能多的爬取数据
非贪婪爬取:在爬取的时候尽可能少的爬取数据
Java 默认使用贪婪爬取,但是在数量词 +,* 后面加上? 就是非贪婪爬取
String str="<h1>hello world</h1>";
//贪婪爬取
String regex="<.*>"
Pattern p=Pattern.compile(regex);
Matcher m=p.matchers(s);
while(m.find()){
System.out.println(m.group());
}
//结果:<h1>hello world</h1>
//分析:贪婪爬取<,*> 其中.*代表所有字符 <代表头部的< >代表尾部的>
//在正则表达式看来是:<h1 hello world /h1>这样的匹配形式
//非贪婪爬取
String regex="<.*?>?"
Pattern p=Pattern.compile(regex);
Matcher m=p.matchers(s);
while(m.find()){
System.out.println(m.group());
}
//结果:<h1>
// </h1>
五,正则表达式在字符串中的使用
- 常用的,还有其他的可以在API帮助文档中查。。。
| 方法名 | 说明 |
|---|---|
| public String[] matches(String 正则表达式) | 判断字符串是否满足正则表达式规则 |
| public String replaceAll(String 正则表达,String 新字符串) | 把满足正则表达式的小串替换为新的字符串 |
| public String[] split(String 正则表达式) | 把满足正则表达式的小串分割 |
六,捕获分组和非捕获分组
正则表达式当中,每一组都是有组号的,也就是序号。
小括号代表的就是分组
-
规则 1:从 1 开始,连续不间断
-
规则 2:以左括号为基准,最左边的是第一组,其次为第二组,依次递推
(\\d+)(\\d*)(\\d?) 其中 (\d+) 代表第一组,(\\d*)第二组,(\\d?)第三组
(\\d+(\\d+))(\\d+) 这里第二个 \\d+ 是第二组!因为规则 2
- 捕获分组:把这一组比如说第二组中的数据,拿出来再用依次
//判断一个字符串的开始字符和结束字符是否一致,只考虑一个字符
举例:a123a b123b 122241 &a3fsfes&
正则表达式:(.).+(.)\\1
\\1表示把第一组的数据(.)拿出来再用一次
\\X 表示把第X组的数据拿出来再用一次
//判断一个字符串的开始和结束字符是否一致,可以有多个字符
举例:abc123abc bbdb123bdbb
正则表达式:(.+).+\\1
//判断一个字符串的开始和结束部分是否一致,开始部分内部的每个字符也需要一致
举例:aaa123aaa bbb123bbb
正则表达式:((.)\\2*).+\\1*
(.)表示把首字母看做一组
//2表示把首字母拿出再次使用
*作用于\\2表示后面重复的内容出现0次或多
.+表示中间任意字符出现1次或多次
\\1表示((.)\\2*)
*表示\\1出现0次或多次
//需求:将字符串:我要学学学编编编编程程程程程程
// 替换为:我要学编程
String str="我要学学学编编编编程程程程程程";
String result=str.replaceAll("(.)\\1+","$1");
replaceAll是String自带的方法,第一个是正则表达式,第二个$1表示在正则表达式中使用第一个分组的内容
在正则表达式中调用分组用 \ 组号 在正则表达式外用分组是用 $ 组号
- 非捕获分组:分组之后不需要在使用本组数据,仅仅只是把数据括起来(不占用组号)
| 符号 | 含义 | 举例 |
|---|---|---|
| (?:正则) | 获取所有 | Java(?:8|11|17) |
| (?=正则) | 获取前面部分 | Java(?=8|11|17) |
| (?!正则) | 获取不是指定内容的前面部分 | Java(?!8|11|17) |