开篇一个栗子:
public class PatternMatcherTest {
public static void main(String[] args) {
/*
正则表达式特殊字符:
^ 匹配一行的开头
$ 匹配一行的结尾
() 标记子表达式
[] 括号内匹配的任意符合字符----->枚举[abc] 范围[a-c] 否[^abc] 并[a-c[A-f]]
{} 字符出现频度
* 前面子表达式出现零次或多次
+ 前面子表达式出现一次或多次
? 前面子表达式出现零次或一次
. 单个字符
\ 转义
| 或 ---------->(x)|(y)|(z表达式)
预定义字符:
\d 0~9的数字
\D 非数字
\s 空白符(空格,制表符,回车符,换页符,换行符等)
\S 非空白符
\w 单词
\W 非单词
*/
/*
Matcher匹配类的几个常用方法:
matchers(String str)
find()
group()
start() end() 返回上一次匹配子串在目标字符串的开始或结束位置
*/
String str = "hello,大家好!我是pengjun,我的电话1是15833978226,电话2是15871979220,电话3是18855667788有事常联系哈!";
Matcher m = Pattern.compile("((158)|(188))\\d{8}").matcher(str);
System.out.println(m.matches()); //false 目标字符串是否与整个正则表达式匹配(强调是整个匹配)
while (m.find()){ //true 目标字符串中是否含有与正则表达式匹配的子串(强调含有)
System.out.print(m.group() + "\t"); //15833978226 15871979220 18855667788
System.out.println("\n开始位置:" + m.start() + "\t结束位置:" + m.end());
}
/*
运行结果:
false
15833978226
开始位置:26 结束位置:37
15871979220
开始位置:42 结束位置:53
18855667788
开始位置:58 结束位置:69
*/
/*
原理:1.Pattern对象多次使用情况:
Pattern模式类的compile方法返回Pattern对象;
Pattern对象通过matcher方法创建一个Matcher匹配对象;
通过Matcher类的方法对匹配的字符串进行操作
2.Pattern对象一次性使用情况:
boolean b = Pattern.Matches(expressStr,str);
*/
}
}
支持数量的标识符:三种匹配模式
- 贪婪模式:正则表达式一般趋向于最大长度匹配,总是尝试匹配尽可能多的字符,也就是所谓的贪婪匹配;
- 勉强模式:属于最小长度匹配,就是匹配到结果就好,总是尝试匹配尽可能少的字符;(在?或*或+或{}后面添加?)
- 占有模式:Java特有的模式,与整个字符串全匹配,比较少用。(在?或*或+或{}后面添加+)
String test1 = "a<tr>aava</tr>abb ";
String test2 = "<tr>";
String reg1 = "<.+>";
System.out.println("贪婪匹配结果:" + test1.replaceAll(reg1,"###"));
String reg2 = "<.+?>";
System.out.println("勉强匹配结果:" + test1.replaceAll(reg2,"###"));
String reg3 = "<.++>";
String reg4 = "<tr>";
System.out.println("占有匹配结果1:" + test1.replaceAll(reg3, "###"));
System.out.println("占有匹配结果2:" + test2.replaceAll(reg4, "###"));
输出结果为:
贪婪匹配结果:a###abb
勉强匹配结果:a###aava###abb
占有匹配结果1:a<tr>aava</tr>abb
占有匹配结果2:###
总结:
贪婪匹配模式属于最大长度匹配,正则表达式引擎会一直匹配到字符串最后,当匹配为false时,通过回溯的方式,倒退找到倒数第一个匹配位置,返回匹配结果;也就是说,这种匹配方式会尽量大范围的匹配,直到匹配了整个内容,这时发现匹配不能成功时,开始回退缩小匹配范围,直到匹配成功
勉强匹配模式于最小长度匹配,正则表达式引擎会匹配到符合pattern的末尾位置那个字符,然后再往后走一步,发现匹配为false,又回溯到找到回退的最近一个匹配为true的位置,返回结果。只要匹配成功,就不再继续尝试匹配更大范围的内容。
占有匹配与贪婪匹配有一定的相似性,那就是都尽量匹配最大范围的内容,直到内容结束,但与贪婪匹配不同的是,完全匹配不再回退尝试匹配更小的范围。
正则表达式环视:
- (?=…) 肯定顺序环视,子表达式能匹配右侧的文本
- (?!..) 否定顺序环视,子表达式不能匹配右侧的文本
- (?<=…) 肯定逆序环视,子表达式能匹配左侧的文本
- (?<!..) 否定逆序环视,子表达式不能匹配左侧的文本
var str = "3123131315896541235啊啊啊13354578956啊啊啊啊13869587563啊啊啊13869587263啊138695872363啊啊";
// 正常手机号 前面不应该有数字并且后面不应该有数字
str.match(/(?<!\d)1[3-9]\d{9}(?!\d)/g)