正则表达式(1)
正则表达式底层实现
案例分析
给定一段文本(字符串),请找出所有四个数字连在一起的子串,如:1998 2020 2021
public static void main(String[] args) {
String context = "1995年,互联网的蓬勃发展给了Oak机会。业界为了使死板、单调的静态网页能够“灵活”起来,……";
// \\d 表示一个任意的数字
String regStr = "\\d\\d\\d\\d";
//创建一个模式对象
Pattern pattern = Pattern.compile(regStr);
//创建一个匹配器
Matcher matcher = pattern.matcher(context);
//开始匹配
while(matcher.find()){
System.out.println("找到:" + matcher.group(0));
}
}
不考虑分组
matcher.find()
- 根据指定的规定,定位满足规则的子字符串(比如1995)
- 找到后将子字符串开始的索引记录到matcher对象的属性 int[] groups;
groups[0] = 0,把该子字符串结束的索引(3)+1的值 记录到 groups[1] = 4- 同时记录oldLast 的值为 子字符串的结束的 索引+1的值即4,即下次执行find时,就从4开始匹配
matcher.group(0)
- 根据group[0] = 0 和 group[1] = 4 的记录的位置,从context 开始截取子字符串[0,4) 返回
- 如果再次执行find方法,仍然按照上面分析来执行
考虑分组
分组:正则表达式中有小括号代表分组,第一个()代表第一组……:(\d\d)(\d\d)
matcher.find()
- 根据指定的规定,定位满足规则的子字符串(比如(19)(95))
- 找到后将子字符串开始的索引记录到matcher对象的属性 int[] groups;
2.1 groups[0] = 0,把该子字符串结束的索引(3)+1的值 记录到 groups[1] = 4
2.2 记录第一组()匹配到的字符串: groups[2] = 0, groups[3] = 2
2.3 记录第二组()匹配到的字符串: groups[4] = 2, groups[5] = 4
…… ……
matcher.group()
group(0) 表示匹配到的整体的子字符串
group(1) 表示匹配到的子字符串的第一个分组
group(2) 表示匹配到的子字符串的第二个分组
注:分组数不能越界
正则表达式语法
元字符(Metacharacter)
转义号 \\
在使用正则表达式去检索某些特殊字符的时候,需要用到转义符号\\,否则检索不到结果,甚至会报错。
注:在java的正则表达式中,两个\\代表其它语言中的一个\。
需要用到转义符号的字符:.*+()$/?[]^{}
如找到左括号(:\\(
字符匹配符
说明
默认区分大小写
选择匹配符 |
限定符 *+?{n} {n,} {n,m}
定位符
b-结束位置 B开始位置
分组
捕获分组
非捕获分组(特别分组)
不能通过使用matcher.group(1) 进行获取
非贪婪匹配
应用实例
- ^[\u0391-\uffe5]+$
- ^[1-9]\\d{5}$
- ^[1-9]\\d{4,9}$
- ^1[3|4|5|8]\\d{9}$
- 获取URL: ^(https:// | http://)?([\\w-]+\\. )+[\\w-]+(\\/[\\w-?=&/#%.]*)?$
——解题思路
对于https://www.bilibili.com/video/BV1Eq4y1E79W?p=17
1)确定url的开始部分(可0次或1次):
(https:// | http://)?
2)确定www.bilibili.(字母数字下划线+.)com(字母数字):
([\\w-]+\\. )+[\\w-]
【注:\\w = [0-9a-zA-Z],+ 一个或多个】
3)确定后面的部分(/video/BV1Eq4y1E79W?p=17)【可能有可能没有】:
(\\/[\\w-?=&/#%.]*)?
【注:?在外面0次或1次,在里面就是实实在在的问号(.也是如此);*——0次或多次】