Java正则表达式学习之分组与替换
正则表达式的子表达式(分组)不是很好懂,但却是很强大的文本处理工具。
1正则表达式热身
匹配电话号码
//电话号码匹配 //手机号段只有13xxx15xxx18xxxx17xxx System.out.println("18304072984".matches("1[3578]\\d{9}"));//true //座机号:010-65784236,0316-3312617,022-12465647,03123312336 Stringregex="0\\d{2}-?\\d{8}|0\\d{3}-?\\d{7}"; StringtelStr="010-43367458"; System.out.println(telStr.matches(regex));//true
匹配邮箱
Stringmail="i@jiaobuchong.com.cn"; Stringreg="[a-zA-Z_0-9]+@[a-zA-Z0-9]+(\\.[a-zA-Z]+){1,2}"; System.out.println(mail.matches(reg));//true
特殊字符替换
将不是中文的字符替换为空:
Stringinput="神探狄仁&*%$杰之四大天王@bdfbdbdfdgds23532"; Stringreg="[^\\u4e00-\\u9fa5]"; input=input.replaceAll(reg,""); System.out.println(input);//神探狄仁杰之四大天王
汉字的Unicode编码范围是:\u4e00-\u9fa5
2分组
组是用括号划分的正则表达式,可以根据组的编号来引用某个组。组号为0表示整个表达式,组号1表示第一对括号扩起的组,以此类推。
看JavaAPI中Pattern中的描述:
Capturinggroupsarenumberedbycountingtheiropeningparenthesesfromlefttoright.Intheexpression((A)(B(C))),forexample,therearefoursuchgroups:
1.((A)(B(C))) 2.(A) 3.(B(C)) 4.(C)
再比如A(B(C))D有三个组:组0是ABCD,组1是BC,组2是C,
可以根据有多少个左括号来来确定有多少个分组,括号里的表达式都称子表达式。
Eg1:
Matcher对象提供很多方法:
- goupCount()返回该正则表达式模式中的分组数目,对应于「左括号」的数目
- group(inti)返回对应组的匹配字符,没有匹配到则返回null
- start(intgroup)返回对应组的匹配字符的起始索引
- end(intgroup)返回对应组的匹配字符的最后一个字符索引加一的值
//这个正则表达式有两个组, //group(0)是\\$\\{([^{}]+?)\\} //group(1)是([^{}]+?) Stringregex="\\$\\{([^{}]+?)\\}"; Patternpattern=Pattern.compile(regex); Stringinput="${name}-babalala-${age}-${address}"; Matchermatcher=pattern.matcher(input); System.out.println(matcher.groupCount()); //find()像迭代器那样向前遍历输入字符串 while(matcher.find()){ System.out.println(matcher.group(0)+",pos:" +matcher.start()+"-"+(matcher.end()-1)); System.out.println(matcher.group(1)+",pos:"+ matcher.start(1)+"-"+(matcher.end(1)-1)); }
输出:
1
${name},pos:0-6
name,pos:2-5
${age},pos:17-22
age,pos:19-21
${address},pos:24-33
address,pos:26-32
group,翻译成中文就是分组。
group()或group(0)对应于整个正则表达式每次匹配到的内容,
group(1)表示括号中(一个子表达式分组)匹配到的内容。
Eg2:
为了更直观的看分组,在Eg1的正则表达式上再多加一对括号:
Stringregex="(\\$\\{([^{}]+?)\\})"; Patternpattern=Pattern.compile(regex); Stringinput="${name}-babalala-${age}-${address}"; Matchermatcher=pattern.matcher(input); //matcher.find()方法会对input这个字符串多次进行匹配,如果能匹配到,这个匹配结果里就会包含多个分组,我们可以从分组里提取我们想要的结果 while(matcher.find()){ System.out.println(matcher.group(0)+",pos:"+matcher.start()); System.out.println(matcher.group(1)+",pos:"+matcher.start(1)); System.out.println(matcher.group(2)+",pos:"+matcher.start(2)); }
输出:
${name},pos:0
${name},pos:0
name,pos:2
${age},pos:17
${age},pos:17
age,pos:19
${address},pos:24
${address},pos:24
address,pos:26
由此可得出一对括号一个分组,可以通过左括号数来确定有多少个分组。
通过group()获取分组中的匹配字串应用场景很广泛,
在笔者的一个项目中,通过使用这个特性实现了很有意思的通配符替换,感动!
Eg3(通过分组提取想要的数据):
//这个正则表达式会提取字符串中的「数字」和「字母」 Patternpattern=Pattern.compile("([0-9]+).*?([a-zA-Z]+)"); Stringinput="那就20200719这样吧sunny。。。。。。。122432该拿什么与眼泪抗衡twinkle"; Matchermatcher=pattern.matcher(input); //每个匹配到的子串分组的个数 intgroup=matcher.groupCount(); //如果输入串有多个可被匹配的子串,这里会多次进行匹配 while(matcher.find()){ System.out.println("匹配到的子串:"+matcher.group());//匹配到的子串 for(inti=1;i<=group;i++){ System.out.println("分组"+i+":"+matcher.group(i)); } }
输出:
匹配到的子串:20200719这样吧sunny
分组1:20200719
分组2:sunny
匹配到的子串:122432该拿什么与眼泪抗衡twinkle
分组1:122432
分组2:twinkle
3分组替换
Eg1:
Stringtel="18304072984"; //括号表示组,被替换的部分$n表示第n组的内容 tel=tel.replaceAll("(\\d{3})\\d{4}(\\d{4})","$1****$2"); System.out.print(tel);//output:183****2984
replaceAll是一个替换字符串的方法,正则表达式中括号表示一个分组,replaceAll的参数2中可以使用$n(n为数字)来依次引用子表达式中匹配到的分组字串,"(\\d{3})\\d{4}(\\d{4})","$1****$2",分为前(前三个数字)中间四个数字(最后四个数字)替换为(第一组数字保持不变$1)(中间为*)(第二组数字保持不变$2)。
Stringone="hellogirlhihot".replaceFirst("(\\w+)\\s+(\\w+)","$2$1"); Stringtwo="hellogirlhihot".replaceAll("(\\w+)\\s+(\\w+)","$2$1"); System.out.println(one);//girlhellohihot System.out.println(two);//girlhellohothi
理解了Eg1,这个例子也自然就理解了。
Eg3:
来一个实用的例子,重复标点符号替换:
Stringinput="假如生活欺骗了你,,,相信吧,,,快乐的日子将会来临!!!…………"; //重复标点符号替换 StringduplicateSymbolReg="([。?!?!,]|\\.\\.\\.|……)+"; input=input.replaceAll(duplicateSymbolReg,"$1"); System.out.println(input);
输出:
假如生活欺骗了你,相信吧,快乐的日子将会来临!……
正则表达式:([。?!?!,]|\\.\\.\\.|……)+,括号中是一个分组:表示一个标点符号,+表示这个分组出现一次或多次,$1分组的内容(一个标点符号)。replaceAll就使用$1去对字符串进行替换了。
Eg4:
IP地址排序
Stringip="192.68.1.254102.49.23.01310.10.10.102.2.2.28.109.90.30"; ip=ip.replaceAll("(\\d+)","00$1"); System.out.println(ip); ip=ip.replaceAll("0*(\\d{3})","$1"); System.out.println(ip); String[]strs=ip.split(""); Arrays.sort(strs); for(Stringstr:strs){ str=str.replaceAll("0*(\\d+)","$1"); System.out.println(str); }
输出:
00192.0068.001.0025400102.0049.0023.000130010.0010.0010.0010002.002.002.002008.00109.0090.0030
192.068.001.254102.049.023.013010.010.010.010002.002.002.002008.109.090.030
2.2.2.2
8.109.90.30
10.10.10.10
102.49.23.13
192.68.1.254
- 让IP地址的每一段都是3位,替换之后有4位的情况
- 保证IP地址每一段都是3位
- 排序之
写到这里,笔者不禁感叹,真的很强大!
4反向引用
使用小括号指定一个子表达式分组后,匹配这个子表达式的文本可以在表达式或其它程序中作进一步的处理。默认情况下,每个分组会自动拥有一个组号,规则是:以分组的左括号为标志,从左向右,第一个分组的组号为1,第二个为2,以此类推。
Eg:
/*这个正则表达式表示安安静静这样的叠词*/ Stringregex="(.)\\1(.)\\2"; System.out.println("安安静静".matches(regex));//true System.out.println("安静安静".matches(regex));//false
上面(.)表示一个分组,里面.表示任意字符,每一个字符都是一个分组,
\\1表示组1(安)又出现了一次,\\2表示组2(静)又出现了一次。
那匹配安静安静,怎么写正则表达式?根据上面的例子,将安静分成一个组,然后这个组又出现了一次就是安静安静:
Stringregex="(..)\\1"; System.out.println("安静安静".matches(regex));//true System.out.println("安安静静".matches(regex));//false
5反向引用替换
Eg1:
Stringstr="我我...我我...我要..要要...要要...找找找一个....女女女女...朋朋朋朋朋朋...友友友友友..友.友...友...友友!!!"; /*将.去掉*/ str=str.replaceAll("\\.+",""); System.out.println(str); str=str.replaceAll("(.)\\1+","$1"); System.out.println(str);
输出:
我我我我我要要要要要找找找一个女女女女朋朋朋朋朋朋友友友友友友友友友友!!!
我要找一个女朋友!
(.)表示任意一个字符都会成为一个分组;\\1+引用分组(一个字符),表示出现1次或多次这个分组。$1引用分组(.)将多个重复字符替换成一个字符。
Eg2:
替换重复出现的两位数之间的内容:
"xx12abdd12345".replaceAll("(\\d{2}).+?\\1","");//结果为xx345
是不是觉得很神奇!
使用replace系列的方法要注意的一个异常:JavareplaceAll()方法报错Illegalgroupreference
参考:
- Java正则篇-27-正则的替换和分组功能
- 正则表达式30分钟入门教程
- 正则基础之——捕获组(capturegroup)
- Java正则表达式Pattern与Matcher类
- Java学习之正则表达式
- Java进阶——使用正则表达式检索、替换String中的特定字符和关于正则表达式的一切
- java去除空格、标点符号
到此这篇关于Java正则表达式学习之分组与替换的文章就介绍到这了,更多相关Java正则表达式分组与替换内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。