[] 可接受的字符列表,例如[abcd]表示匹配a、b、c、d中任意一字符
[^] 不可接受的字符列表 [^abc] 除a,b,c之外的任意一个字符,包括数字和特殊符号
[^a-z]表示不匹配a-z中的任意一个字符
[^a-z]{2} {2}表示连续2个字符不是a-z的字符,如A111匹配结果11
[^0-9]表示不匹配0至9中任意一个字符
符号 - 符号 - 连字符 A-Z 任意单个大写字母
符号. 匹配除\n以外的任何字符 a..b表示以a开头,以b结尾,中间包括2个任意字符长度为4的字符串,如aaab,aefb,a35b,a*&b
\\d 匹配单个数字字符,相当于[0-9]
\\d{3} 等价与\\d\\d\\d
\\d{3}(\\d)? 包含3个或4个数字的字符串,如123,8765等
\\D 匹配单个非数字字符,相当于[^0-9]
\\D(\\d)* 表示以单个非数字字符开头,后接任意个数字字符串,如f、d1234等
\\w 匹配单个数字,大小写字母,下划线,相当于[0-9a-zA-Z_]
\\d{3}\\w{4} 表示以3个数字字符开头的长度为7的字符串
\\W 匹配单个非数字、大消息字母字符,相当于[^0-9a-zA-Z_]
\\W+\\d{2} 表示匹配至少一个非数字,非字母字符开头,2个数字字符结尾的字符串 如#26,#?@67
选择匹配符号| ,表示匹配"|"之前或之后的表达式,如 ab|cd 表示匹配ab或者cd
符号* 表示指定字符重复0次或者n次,如(abc)* ,仅包含任意个abc的字符串,等效与\W*,匹配abc、abcabcabc
符号+ 表示指定字符重复1次或n次(至少一次),m+(abc)*,以至少1个m开头,后接任意个abc的字符串,m,mabc,mabcabc
(?i)abc 表示不区分大小写,匹配abc、Abc等
a(?i)bc或者a(?i)(bc) 表示bc不区分大消息
也可以手动指定不区分大小写
Pattern pattern = Pattern.compile(regStr, Pattern.CASE_INSENSITIVE);
\\s 匹配任何空白字符(空格,制表符等)
\\S 匹配任何非空白字符,和\s刚好相反
.匹配出\n之外的所有字符,如果要匹配.本身,则需要使用\\.
限定符 *+?{}
* 指定的字符重复0次或n次,即0到多;如(abc)匹配abc,abcabc等
+ 指定字符重复1次或n次,如a+(bcd)*匹配至少1个a开头,人一个bcd结尾的字符,如a,abcd,abcdbcd等
?指定字符重复0或1次,如a+bc?表示至少一个a开头,b或者bc结尾的字符串,如ab或者abc,aabc等
{n}只能输入n个字符,如[abcd]{3},表示由a,b,c,d中字母组成的任意长度为3的字符串,如abc,acd,adc等
{n,}至少n次匹配,[abcd]{3,}表示由abcd中字母组成的任意长度不小于3的字符串,如abc,aab等
{n,m}指定至少n个但不多余m个匹配,[abcd]{3,5}表示由abcd中字母组成的任意长度在3到5之间的字符串,如abc,adddd等;
定位符"^" "$" "\b" "\B"
^指定起始字符,如^[0-9]+[a-z]*表示至少一个数字开头,任意个小写字母结尾的字符串,如9a,8等;
$指定结束字符,^[0-9]\\-[a-z]$表示以一个数字开头,后接-,并以a到z任意一个字母结尾
^[0-9]\\-[a-z]+$表示以一个数字开头,后接-,并以a到z任意一个或多个字母结尾
\\b 匹配目标字符串的边界,边界指存在空格或者结尾,如aa\\b匹配kkkaa,kkaa,kk aa等
\\B匹配目标字符串的非边界,边界指开头或者空格,如aa\\B,匹配aadkkklll,aa88,aa uu等
分组
1.非命名捕获
(pattern) 非命名捕获,捕获匹配的字符串,编号为0的第一个捕获是由整个正则表达式模式匹配的文本,其他捕获结果则根据左括号的顺序从1开始自动编号
代码实例
String content = "huawei nanjing2022 hua0318sheng";
String regExp = "(\\d\\d)(\\d\\d)";
Pattern pattern = Pattern.compile(regExp);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
System.out.println(matcher.group(0));
System.out.println(matcher.group(1));
System.out.println(matcher.group(2));
System.out.println("------");
}
输出
2022
20
22
------
0318
03
18
------
2.命名捕获
(?pattern)命名捕获,将匹配的子字符串捕获到一个组名称或编号名称中,用于name的字符串不能包含任何标点符号,并且不能以数字开头,可以使用单引号替代尖括号,如(?'name')
代码实例
String content = "huawei nanjing2022 hua0318sheng";
String regExp = "(?\\d\\d)(?\\d\\d)";
Pattern pattern = Pattern.compile(regExp);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
System.out.println(matcher.group(0));
System.out.println(matcher.group(1));
System.out.println(matcher.group(2));
System.out.println(matcher.group("group1"));
System.out.println(matcher.group("group2"));
System.out.println("------");
}
输出
2022
20
22
20
22
------
0318
03
18
03
18
------
3.非捕获匹配(?:pattern)
表示匹配pattern,但不捕获匹配的子表达式,对于用or字符"|"组合模式部件的情况很有用,例如huaweinanjing|huaweishenzhen 比huawei(?:nanjing|shenzhen)要繁琐
代码实例
// String regExp = "huaweinanjing|huaweishenzhen|huaweihangzhou";
String regExp = "huawei(?:nanjing|shenzhen|hangzhou)";
String content = "hello huaweinanjing huaweishenzhen huaweihangzhou";
Pattern pattern = Pattern.compile(regExp);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
System.out.println(matcher.group(0));
}
运行结果
huaweinanjing
huaweishenzhen
huaweihangzhou
4.非捕获匹配(?=pattern)
(?=pattern)限定了捕获的范围,如tigger(?=3|5|7)匹配tigger3中的tigger,不匹配tigger2中的tigger
代码实例
String regExp = "tigger(?=3|5|7)";
String content = "tigger2 tigger3 tigger5";
Pattern pattern = Pattern.compile(regExp);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
System.out.println(matcher.group(0));
}
输出
tigger // tigger3中的tigger
tigger // tigger5中的tigger
5.非捕获匹配(?!pattern)
该表达式匹配不处于匹配pattern的字符串的起始点的搜索字符串,如tigger(?!3|5|7)不匹配tigger3中tigger,不匹配tigger5中的tigger,不匹配tigger7中的tigger,但可以匹配tigger2中的tigger
代码实例
String regExp = "tigger(?!3|5|7)";
String content = "tigger2 tigger3 tigger5";
Pattern pattern = Pattern.compile(regExp);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
System.out.println(matcher.group(0));
}
输出
tigger // tigger2中的tigger
元字符说明
^、$、?(默认非贪婪,如\\d+改成非贪婪匹配\\d+?只匹配一个)
常用场景
1.校验字符串是否是汉字
// 校验字符串是否是汉字
String content = "华为";
String regExp = "^[\u0391-\uffe5]+$";
Pattern pattern = Pattern.compile(regExp);
Matcher matcher = pattern.matcher(content);
if (matcher.find()) {
System.out.println("是汉字");
} else {
System.out.println("不全部是汉字");
}
2.校验字符串是否是邮政编码
// 校验字符串是否是邮政编码
String content = "236566";
// 1-9开头,紧接着是5位数字结尾
String regExp = "^[1-9]\\d{5}$";
Pattern pattern = Pattern.compile(regExp);
Matcher matcher = pattern.matcher(content);
if (matcher.find()) {
System.out.println("是");
} else {
System.out.println("否");
}
3.校验字符串是否是QQ号码
// 校验字符串是否是QQ号码
String content = "383754990";
// 1-9开头,总长度在5到10位的数字
String regExp = "^[1-9]\\d{4,9}$";
Pattern pattern = Pattern.compile(regExp);
Matcher matcher = pattern.matcher(content);
if (matcher.find()) {
System.out.println("是");
} else {
System.out.println("否");
}
4.校验字符串是否是手机号码
// 校验字符串是否是手机号码
String content = "15276876755";
// 13,14,15,18开头的11位数字
String regExp = "^1[3|4|5|8]\\d{9}$";
Pattern pattern = Pattern.compile(regExp);
Matcher matcher = pattern.matcher(content);
if (matcher.find()) {
System.out.println("是");
} else {
System.out.println("否");
}
5.校验字符串是否是URL
String content = "https://www.bilibili.com/video/BV11A41157Sa?spm_id_from=333.999.0.0";
// 1. ^((http|https)://) 匹配https://
// 2. ([\w-]+\.)+[\w-]+ 匹配www.bilibili.com
// 3. (/[\w-?=&/%.#]*)? 匹配 /video/BV11A41157Sa?spm_id_from=333.999.0.0
// [\w-?=&/%.]匹配?,=,&,/,%,.等
// [.]等价于//. 匹配.本身
// . 匹配除\n之外的所有字符
String regExp = "^((http|https)://)?([\\w-]+\\.)+[\\w-]+(\\/[\\w-?=&/%.#]*)?$";
Pattern pattern = Pattern.compile(regExp);
Matcher matcher = pattern.matcher(content);
if (matcher.find()) {
System.out.println("是");
} else {
System.out.println("否");
}
整体匹配
String content = "hello nanjing";
// String regExp = "hello"; // false
String regExp = "hello.* "; // true .*代表任意个字符
// 整体匹配
boolean matches = Pattern.matches(regExp, content);
System.out.println(matches);
注意事项:整体匹配Pattern.matches()与matcher.find()存在一定区别,前者是整体匹配,后者是局部匹配,正则表达式上存在一些区别,不能混用。
整体匹配与局部匹配区别的代码实例
String content = "hello nanjing";
String regExp = "hello"; // false
// String regExp = "hello.* "; // true .*代表任意个字符
// 整体匹配
boolean matches = Pattern.matches(regExp, content);
System.out.println(matches);
System.out.println("---------------");
Pattern pattern = Pattern.compile(regExp);
Matcher matcher = pattern.matcher(regExp);
if (matcher.find()) {
System.out.println("存在匹配的串");
} else {
System.out.println("不存在匹配的串");
}
输出:
false
---------------
存在匹配的串
分组、反向引用、捕获
分组:用圆括号组成一个比较复杂的匹配模式,这个圆括号的部分可以看作是一个子表达式,也即一个分组
反向引用:圆括号的内容被捕获后,可以在这个括号后被使用,从而写出一个比较实用的匹配模式,这个我们称为反向引用,这种引用既可以是在正则表达式的内部,也可以是在正则表达式的外部,内部反向引用\分组号,外部反向引用$分组号
捕获:把正则表达式中子表达式/分组匹配的内容保存到内存中以数字编号或显式命名的组里,方便后面引用,从左向右以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推,组0代表的是整个表达式
分组,反向引用,捕获的代码实例
String regExp = "(\\d)\\1"; // 表示连续两位相同的数字,匹配如11、44、55等
String regExp = "(\\d)(\\d)\\2\\1"; // 表示连续的四位数字,1与4位相同,2与3位相同,匹配如1221、3223等
String regExp = "\\d{5}-(\\d)\\1{2}(\\d)\\2{2}(\\d)\\3{2}"; // 匹配连续5位的数字,后面连-,后面连续9位数字,其中每连续3位是相同的情况,如22221-777888999等
口吃去重实例:要求去掉一句话中连续重复的冗余字符,只保留一个即可,如"我....我是中..中.国南南南京人",需要去掉“.”以及连续出现的字符,最终变成“我是中国南京人”
String content = "我....我是中..中.国南南南京人";
// 1.先去掉所有的.
String dotRegExp = "\\.";
Pattern pattern = Pattern.compile(dotRegExp);
Matcher matcher = pattern.matcher(content);
content = matcher.replaceAll("");
// 2.去掉连续重复的字符,只保留一个
// "(.)\\1+"表示匹配任意多个连续字符
// "$1"外部引用,使用第一个字符替换连续重复的字符
Pattern.compile("(.)\\1+").matcher((content)).replaceAll("$1");
String类中使用正则表达式
校验手机号是否138或者139开头,且长度11位
String content = "13887667805";
String regExp = "13(?:8|9)\\d{8}";
if (content.matches(regExp)) {
System.out.println("合法");
} else {
System.out.println("非法");
}
替换字符串中特定字符串
// 使用南京替换nanjing
String content = "nanjing1 是一座美丽的城市,nanjing2拥有悠久的历史,丰厚的文化底蕴...";
content = content.replaceAll("nanjing(?:1|2)", "南京");
System.out.println(content);
指定分割符分割字符串
// 分隔符为+、=、*、-等符号
String content = "hell-o+nanjing=yuhua+998*77777";
String[] array = content.split("\\*|-|=|\\+");
for (String arr : array) {
System.out.println(arr);
}
常用场景
验证邮箱合法性
// .在中[]中表示.本身
// ^[\w-]+ 表示字符开头,长度1到N位
// @ 表示@本身
// ([a-zA-Z0-9]+\\.)+ 表示1到N组"字母数字."的组合,如cn.;com.;edu.cn.等
// [a-zA-Z0-9]+ 表示字母数字组合长度1到N位不等
String regExp = "^[\\w-]+@([a-zA-Z0-9]+\\.)+[a-zA-Z0-9]+";
String content = "[email protected]";
System.out.println(content.matches(regExp));
解析URL
注意:下面的代码逻辑只具有一定的参考性,具体解析规则要根据实际要求来定
String content = "https://www.bilibili.com/video/BV11A41157Sa?spm_id_from=333.999.0.0&name=zhangsan";
// 采用分组方式处理
String regExp = "([a-zA-Z]+)://([\\w-.]+)(:\\d+|)([/\\w-]*)([?]*)([[\\w_.]*=[\\w_.]*&*]+)";
Pattern pattern = Pattern.compile(regExp);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
System.out.println(matcher.group(0));
// 协议
System.out.println(matcher.group(1));
// 域名
System.out.println(matcher.group(2));
// 路径
System.out.println(matcher.group(4));
// 参数列表
System.out.println(matcher.group(6));
}
常用正则表达式参考
数字 :^[0-9]*$
n位的数字:^\d{n}$
至少n位的数字:^\d{n,}$
m-n位的数字:^\d{m,n}$
零或者非零开头的 数字:^(0|[1-9][1-9]*)$
非零开头的最多带两位小数的数字:^([1-9][0-9*])+(.[0-9]{1-2})?$
带1-2位小数的正数或负数:^(\-)?\d+(\.\d{1,2})?$
正数、负数和小数:^(\-|\+)?\d+(\.\d+)?$
两位小数的正数:^[0-9]+(.[0-9]{2})?$
有1-3位小数的正数:^[0-9]+(.[0-9]{1,3})?$
非零的正整数:^[1-9][0-9]*$或^[1-9]\d*$等
非零的负整数:^-[1-9]\\d*$
非负整数:^\\d+$或者^[1-9]\\d*|0$
非正整数:^-[1-9]\\d*|0$或者^((-\\d+)|(0+))$
非负浮点数:^\\d+(\\.\\d+)?$
非正浮点数:^((-\\d+(\\.\\d+)?)|(0+(\\.0+)?))$
正浮点数:^[1-9]\\d*\\.\\d*|0\\.\\d*[1-9]\\d*$
负浮点数:^-([1-9]\\d*\\.\\d*|0\\.\\d*[1-9]\\d*$
浮点数:^(-?\\d+)(\\.\\d+)?$
校验字符表达式
汉字:^[\u4e00-\u9fa5]+$
英文和数字:^[A-Za-z0-9]+$
长度为3-20的所有字符:^.{3,20}$
中文,英文,数字包括下划线:^[\u4e00-\u9fa5A-Za-z0-9_]+$
可以输入含有^T%,;=?$\等字符:[^T%,;=?$\x22]+
禁止输入含有~的字符[^~\x22]+