精确匹配,也就是如出一辙java
System.out.println("t".matches("t")); // true
System.out.println("t*".matches("t\\*")); // true 注意对于通常字符串 *不是特殊字符 在正则中*是特殊字符,所以要表达其原本的意思须要使用转义(此转义时正则中的转义,不是通常的转义字符),即\*,可是\*并不是标准的转义字符,所以使用\字符与*字符拼接标识转义(此转义时正则中的转义,而不是通常字符串中的转义),而表达字符则须要\\
System.out.println("$".matches("\\$")); // true
System.out.println("\t".matches("\t")); // false 正则匹配转义字符,源字符串解析不解析为转义
System.out.println("\t".matches("\\t")); // true正则从左到右匹配,在正则中用到了对于\的转义标识\字符串自己,这里匹配时把普通字符串中的转义字符视为两个字符,至关于精确匹配
System.out.println("\\t".matches("\\t")); // false
System.out.println("\\t".matches("\\\\t")); // true 正则表达式中匹配转义,源字符串不匹配转义
复制代码
对于正常的字符串来讲,除了普通字符和转义字符以外,特殊字符有以下几个git
\
做为转义字符的标识符,若是想不作为标识符使用,而是单独做为字符串自己使用,必须使用\\
github
'
单引号,Java的字符,js的字符串,均可以使用单引号标识,所以为了不混淆使用\'
标识单引号自己正则表达式
"
双引号,多种语言的字符都使用双引号标识,为了不混淆使用\"
标识双引号字符自己markdown
正则接受通常的转义字符,也接受正则本身引入的所谓的转义字符(提供正则功能)oop
\
与后边的被转译字符视为一个字符(事实上也确实如此),而对于正则本身引入的转义字符,\
与后边的被转译字符视为两个字符,只不过这种字符组合构成了转义的功能
System.out.println("t*".matches("t\\*"));
\w \d
使用正则表达式引擎提供的特殊字符时务必注意不要与转义字符混淆post
转义字符的做用是让一个特殊字符失去其自己的含义,而做为一个普通的字符,对于普通字符来讲即便使其具备特殊的含义性能
特殊字符以及其自己含有的特殊含义包括:学习
表示惟一匹配(匹配有限数量的字符)网站
. 匹配一个而且必须是1个的除了换行符以外的任意字符
\d
匹配一个数字
\D
除了数字以外的字符
\w
字母、数字、下划线
\W
除了字母、数字、下划线以外的字符
\s
空白字符(空格+制表符+换页符+换行符)
\S
除了空白字符以外的其余字符
指定范围的匹配
[123]
枚举匹配
[n-m1-2A-b]
指定范围匹配(范围的起始点与终止点都包含)(注意多范围之间无空格)
使用^取非
注意仅在范围匹配,也就是方括号内部使用^
作取非除了上述的特殊字符外,正则还提供了一些其余的特殊字符,部分特殊字符与普通的转义字符重复
重复匹配(匹配无限数量的字符)(通配符+集合区间)(重复匹配做为修饰符放在惟一匹配的字符后边)
匹配任意多个符合规则的字符
匹配至少一个
?
匹配0个或者1个
{n}
匹配n个{n,m}
匹配至少n个,至多m个,m省略表示至少含义,n设置为0表示至多含义对于普通字符的转义
正则表达式中须要进行转义以表示字符自己的特殊字符
.
?
$
^
方括号
圆括号
大括号
|
\
\b
字符边界(注意这个正则的特殊字符与普通转义字符中有重复,在正则中显然做为字符边界处理)
\B
标识非字符边界
案例
String p = "The cat scattered his food all over the room.";
System.out.println(p.replaceAll("\\bcat\\b", "*")); // The * scattered his food all over the room.
复制代码
适用于多行匹配的模式下对于字符串的匹配
^
标识字符串的开头
是否使用^
边界符号的区别在于,是不是针对整个字符串的匹配
"(T|t)he" => The car is parked in the garage. // 字符串中的两个the都会被选中
"^(T|t)he" => The car is parked in the garage. // 只有字符串首部的The被选中,由于筛选的是以The或者the开头的字符串
复制代码
$
标识字符串的结尾
一样的,是否使用$
边界符号的区别在于,是不是针对整个字符串的匹配
"(at\.)" => The fat cat. sat. on the mat. // cat. sat. mat.都被选中
"(at\.)$" => The fat cat. sat. on the mat. // 只有最后一个mat.被选中
复制代码
字符串边界符号与正则模式的配合使用
在多行字符串的匹配中当只是用字符串边界符号时,仅仅能匹配第一行或最后一行,由于有换行符的存在因此只能匹配一行
String p1 = String.join("\n", "I am scq000.", "I am scq000.");
// *
// I am scq000.
System.out.println(p1.replaceAll("^I am scq000\\.", "*"));
// I am scq000.
// *
System.out.println(p1.replaceAll("I am scq000\\.$", "*"));
// 多行没法匹配
// I am scq000.
// I am scq000.
System.out.println(p1.replaceAll("^I am scq000\\.$", "*"));
复制代码
多行匹配的引入
System.out.println(p1.replaceAll("(?m)^I am scq000\\.$", "*"));
复制代码
(?m)
引入多行模式Pattern p = Pattern.compile("^I am scq000\\.$", Pattern.MULTILINE);
Matcher m = p.matcher(p1);
System.out.println(m.find());
复制代码
Pattern p1 = Pattern.compile("^.*b.*$");
//输出false,由于正则表达式中出现了^或$,默认只会匹配第一行,第二行的b匹配不到。
System.out.println(p1.matcher("a\nb").find());
Pattern p2 = Pattern.compile("^.*b.*$",Pattern.MULTILINE);
//输出true,指定了Pattern.MULTILINE模式,就能够匹配多行了。
System.out.println(p2.matcher("a\nb").find());
复制代码
"/.at(.)?$/" => The fat
cat sat
on the mat. 只有mat匹配
"/.at(.)?$/gm" => The fat
cat sat
on the mat. fat sat mat都匹配
复制代码
m
多行模式
g
全局模式 匹配所有的符合规则的而不仅是第一个
i
忽略大小写
指定模式的两种方式:
在正则表达式中指定
String p1 = String.join("\n", "I Am scq000.", "I am scq000.");
// 结果为:
// I Am scq000.
// *
// 可见第一行并未匹配
System.out.println(p1.replaceAll("I am scq000\\.", "*"));
// 多行模式 大小写无关模式
// 结果为:
// *
// *
// 可见所有都匹配
System.out.println(p1.replaceAll("(?mi)I am scq000\\.", "*"));
复制代码
(?m)
(?i)
来标识正则模式,也可使用组合模式(?mi)
replaceAll
replaceFirst
在API参数中指定
Pattern p1 = Pattern.compile("^.*b.*$");
//输出false,由于正则表达式中出现了^或$,默认只会匹配第一行,第二行的b匹配不到。
System.out.println(p1.matcher("a\nb").find());
Pattern p2 = Pattern.compile("^.*b.*$",Pattern.MULTILINE);
//输出true,指定了Pattern.MULTILINE模式,就能够匹配多行了。
System.out.println(p2.matcher("a\nb").find());
复制代码
Pattern解析正则时除了提供了多行模式外,还提供了如下几种模式
DOTALL模式 用来解决正则表达式中的.
通配符不包含换行符带来的问题
Pattern p1 = Pattern.compile("a.*b");
//输出false,默认点(.)没有匹配换行符
System.out.println(p1.matcher("a\nb").find());
Pattern p2 = Pattern.compile("a.*b", Pattern.DOTALL);
//输出true,指定Pattern.DOTALL模式,能够匹配换行符。
System.out.println(p2.matcher("a\nb").find());
复制代码
UNIX_LINES
CASE_INSENSITIVE
LITERAL
UNICODE_CASE
CANON_EQ
UNICODE_CHARACTER_CLASS
同时使用多个模式的案例
Pattern p1 = Pattern.compile("^a.*b$");
//输出false
System.out.println(p1.matcher("cc\na\nb").find());
Pattern p2 = Pattern.compile("^a.*b$", Pattern.DOTALL);
//输出false,由于有^或&没有匹配到下一行
System.out.println(p2.matcher("cc\na\nb").find());
Pattern p3 = Pattern.compile("^a.*b$", Pattern.MULTILINE);
//输出false,匹配到下一行,但.没有匹配换行符
System.out.println(p3.matcher("cc\na\nb").find());
//指定多个模式,中间用|隔开
Pattern p4 = Pattern.compile("^a.*b$", Pattern.DOTALL|Pattern.MULTILINE);
//输出true
System.out.println(p4.matcher("cc\na\nb").find());
复制代码
以上各个模式的用途可查看源码注释,每个模式都支持对应的正则表达式内嵌的标识方法,能够参考其注释
回溯引用是在分组的基础之上使用的,指的是模式的后边的部分引用前边部分的已经匹配了的子表达式,使用回溯表达式有如下两点好处
能够写出更加精简高效的正则
\1
,\2
,....,其中\1
表示引用的第一个子表达式,\2
表示引用的第二个子表达式,以此类推。而\0
则表示整个表达式Hello what what is the first thing, and I am am scq000.
---\b(\w+)\s\1
可使用正则抽取分组信息
Pattern类配合Matchr类
String regex20 = "([0-9]{3,4})-([1-9]{7,8})";
Pattern pattern = Pattern.compile(regex20);
Matcher matcher = pattern.matcher("0312-2686815");
// 注意只有通过matches判断后的matcher才能进行分组提取,不然会报错No Match Fund
if (matcher.matches()) {
// 注意分组从1开始,序号为0的分组是字符串总体
// 区号
System.out.println(matcher.group(1));
// 电话号
System.out.println(matcher.group(2));
// 匹配的总体
System.out.println(matcher.group(0));
} else {
System.out.println("不匹配");
}
// 去掉区号
System.out.println("0312-2686815".replaceAll(regex20, "$2"));
复制代码
"str.matches"
方法内部使用的也是Pattern与Matchr,每一次调用方法都建立一个新的Patterm对象和一个新的Matcher对象,推荐直接定义一个Pattern来复用,以提高性能$1
而不是\1
,一样注意$0
表明总体,$1
才是第一个分组,以此类推若是要拒绝子正则表达式被引用,则在子正则的前边加上?:
String regex20 = "(?:[0-9]{3,4})-([1-9]{7,8})";
// $0仍然是表示总体,$1由第二个子表达式补位,此时再引用$2 会报错No Group 2
System.out.println("0312-2686815".replaceAll(regex20, "$2"));
复制代码
由上边的非捕获正则?:
引出前向查找和后向查找(也能够称做零宽度断言)----相对来讲说比较难以理解
(?=regex)
"(T|t)he(?=\sfat)" => The fat cat sat on the mat.
匹配第一个The fat
(?!regex)
"(T|t)he(?!\sfat)" => The fat cat sat on the mat.
匹配第二个the(?<=regex)
"(?<=(T|t)he\s)(fat|mat)" => The fat cat sat on the mat.
匹配fat和mat(?<!regex)
"(?<!(T|t)he\s)(cat)" => The cat sat on cat.
匹配第二个cat|
或关系[^]
枚举或指定范围的匹配的取反!
负先发断言,负后发断言"/(.*at)/" => The fat cat sat on the mat.
整个字符串所有匹配?
便可:将?
加在重复匹配的修饰符(*
+
?
等)后边便可"/(.*?at)/" => The fat cat sat on the mat.
at
前边是任意数量的字符,惰性匹配就在这个任意数量的修饰符后加上?
标识尽量少匹配字符 所以只匹配The fat
123000
-> "(\\d+)(0*)"
-> "123000" ""
至少一个数字?我全都要123000
-> "(\\d+?)(0*)"
-> "123" "000"
至少一个数字?那就给你1个吧!可是考虑到后边的只想要0,那就把0前边的都给你0000
-> "(\\d+?)(0*)"
-> "0" "000"
至少一个数字,那就给你1个,其他的后边的正好都要!哈哈9999
-> "(\\d??)(9*)"
-> "" "9999"
无关紧要,正好后边都想要呢,那你就没了~