概念:
正则表达式:符合一定的规则的表达式,实际是用来操作字符串的一些规则。
作用:用于专门操作字符串。
好处:正则的出现,对字符串的复杂操作变得更为简单。
特点:将对字符串操作的代码用一些符号来表示。只要使用了指定符号,就可以调用底层的代码对字符串进行操作。符号的出现,简化了代码的书写。
弊端:符号的出现虽然简化了书写,但是却降低了阅读性。
其实更多是用正则解决字符串操作的问题。
组:用小括号标示,每定义一个小括号,就是一个组,而且有自动编号,从1开始。只要使用组,对应的数字就是使用该组的内容。别忘了,数组要加\\。(aaa(wwww(ccc))(eee))技巧,从左括号开始数即可。有几个左括号就是几组。
正则表达式的具体操作功能:
一.匹配(match):
String match方法。用规则匹配整个字符串。只要有一处不符合规则,就匹配结束,返回false。
例1代码:
String str="abc efg ABC";
String regEx="a|f"; //表示a或f
Pattern p=Pattern.compile(regEx);
Matcher m=p.matcher(str);
boolean rs=m.find();
提示:如果str中有regEx,那么rs为true,否则为flase。如果想在查找时忽略大小写,则可以写成Pattern p=Pattern.compile(regEx,Pattern.CASE_INSENSITIVE);
例2代码:String regEx=".+\\\\(.+)$";
String str="c:\dir1\dir2\name.txt";
Pattern p=Pattern.compile(regEx);
Matcher m=p.matcher(str);
boolean rs=m.find();
for(int i=1;i<=m.groupCount();i++){
System.out.println(m.group(i));
}
以上的执行结果为c:\dir1\dir2\name.txt,name.txt,提取的字符串储存在m.group(i)中,其中i最大值为m.groupCount();
提示:"\\"匹配"\\\\"
二.切割(split):
其实用的就是String类中的split方法。
代码片段:
private static void spilit(){
String regEx="::";
Pattern p=Pattern.compile(regEx);
String str="xd::abc::cde";
String[] r=p.split(str);
//执行后,r就是{"xd","abc","cde"},其实分割时还有更简单的方法
//String[] r=str.split("::");
for(String s:r){
System.out.println(s);
}
打印结果为:
xd
abc
cde
切割叠词:
1.按照叠词完成切割,为了可以让规则的结果被重用。
2.可以将规则封装成一个组,用()完成,组的出现都有编号从1开始。
3.想要使用已有的组可以通过\n(n就是组的编号)的形式来获取的。
代码如下:
private static void overlapsp() {
String regEx = "(.)\\1+";
String str = "abbcdddddefffffgz";
Pattern p = Pattern.compile(regEx);
String arr[] = p.split(str);
for (String s : arr) {
System.out.println(s);
}
}
打印结果:
a
c
e
gz
三.替换(replace)
替换:其实用的就是String类中的replaceAll();
需求:将字符串"aaabbced a ccdeaa"中连续的a替换为A
代码如下:
private static void replace() {
String regEx = "a+"; // 表示一个或多个a
Pattern p = Pattern.compile(regEx);
Matcher m = p.matcher("aaabbced a ccdeaa");
String s = m.replaceAll("A");
System.out.println(s);
}
打印结果为:Abbced A ccdeA
四.查找()获取:
1)先要将正则表达式编译成正则对象。使用的是Pattern中静态方法 compile(regex);
2)通过Pattern对象获取Matcher对象。
Pattern用于描述正则表达式,可以对正则表达式进行解析。
而将规则操作字符串,需要从新封装到匹配器对象Matcher中。然后使用Matcher对象的方法来操作字符串。
如何获取匹配器对象呢?
通过Pattern对象中的matcher方法。该方法可以正则规则和字符串想关联。并返回匹配器对象。
3)使用Matcher对象中的方法即可对字符串进行各种正则操作。
需求:将字符串”ming tian jiuyao fangjia le, da jia“中连续出现四个字符的子串查找获取出来并打印。
实现代码如下:
private static void getDemo() {
// TODO Auto-generated method stub
String str="ming tian jiuyao fang jia le,da jia";
String reg="\\b[a-z]{4}\\b";
Pattern p=Pattern.compile(reg);
Matcher m=p.matcher(str);
while(m.find()){
System.out.println(m.group());
System.out.println(m.start()+"..."+m.end());
}
}
打印结果:
ming
0...4
tian
5...9
fang
17...21
五.综合练习:
问题:将下列字符串转成:我要吃饭"。到底用四种功能的哪一种呢?或者是哪几个呢?
思路方法:
1.如果想知道该字符是否对或错,使用匹配。
2.想要按照自定义的方式将字符串变成多个字符串,则用切割,获取规则以外的子串。
3.想要将已有的字符串变成另一字符串:替换。
4.想要拿到符合需求的字符串子串:获取。获取符合规则的子串。
代码如下:
private static void test1(){
String str="我我....要要....吃吃....饭饭...";
str =str.replaceAll("\\.+", "");
System.out.println(str);
str=str.replaceAll("(.)\\1+", "$1");
//$1代表第一组,若replace方法后写的是类似$1 $2 $3...表示用第1 2 3...组去替代原来符合第一个参数正则表式
//(xx(xx(A)))\\n中的\\n表示这里捕获引用了第n组。
System.out.println(str);
}
打印结果如下:我我要要吃吃饭饭
我要吃饭
另外一个关于组的事例代码:
问题:
将:192.168.1.254 102.49.23.013 10.10.10.10 2.2.2.2 8.109.90.30按照大小排序并打印
思路:
1.按照没一段需要的最多的0进行补充,那么每一段就会至少保证有3位
2.将每一段只保留3位。这样。所有的ip地址都是每一段三位,然后按照自然排序对不同的ip排序,并把前面的0去掉打印。
private static void ipSort(){
String ip="192.168.1.254 102.49.23.013 10.10.10.10 2.2.2.2 8.109.90.30";
/*ip=ip.replaceAll("0*(\\d+)", "00$1");
System.out.println(ip);*/
ip=ip.replaceAll("(\\d+)", "00$1");
System.out.println(ip);
ip=ip.replaceAll("0*(\\d{3})","$1");
//其实第一个参数正则表达式还有其他两种写法:0*(\\d+?)跟0*(\\d++),但0*(\\d+?)这种写法会得出错误结//果,这是与量词有关稍 后会做出解释
System.out.println(ip);
String[] arr=ip.split(" ");
TreeSet<String> ts=new TreeSet<String>();
for(String s:arr){
ts.add(s);
}
for(String s:ts){
s=s.replaceAll("0*(\\d+)","$1");
System.out.println(s);
}
}
打印结果为:
00192.00168.001.00254 00102.0049.0023.00013 0010.0010.0010.0010 002.002.002.002 008.00109.0090.0030
192.168.001.254 102.049.023.013 010.010.010.010 002.002.002.002 008.109.090.030
2.2.2.2
8.109.90.30
10.10.10.10
102.49.23.13
192.168.1.254
六.正则表达式的量词:
1.Greedy 数量词:
X? X,一次或一次也没有
X* X,零次或多次
X+ X,一次或多次
X{n} X,恰好 n 次
X{n,} X,至少 n 次
X{n,m} X,至少 n 次,但是不超过 m 次
2.Reluctant 数量词:
X?? X,一次或一次也没有
X*? X,零次或多次
X+? X,一次或多次
X{n}? X,恰好 n 次
X{n,}? X,至少 n 次
X{n,m}? X,至少 n 次,但是不超过 m 次
3.Possessive 数量词:X?+ X,一次或一次也没有
X*+ X,零次或多次
X++ X,一次或多次
X{n}+ X,恰好 n 次
X{n,}+ X,至少 n 次
X{n,m}+ X,至少 n 次,但是不超过 m 次
4.它们之间的差别:
正则表达式默认是贪婪匹配(Greedy),可以理解为最大范围匹配。可如果是非贪婪匹配(Reluctant)他就尽可能小的匹配。侵占匹配(possessive)在匹配不成功后不会产生回溯,一般很少用到,只有在正则表达式优化中会用到
贪婪在匹配不成功后会产生回溯。
以下是的代码反映三者区别:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexDemo2 {
public static void main(String args[]) {
Demo2();
}
private static void getDemo() {
// TODO Auto-generated method stub
String str = "ming tian jiuyao fang jia le,da jia";
String reg = "\\b[a-z]{4}\\b";
Pattern p = Pattern.compile(reg);
Matcher m = p.matcher(str);
while (m.find()) {
System.out.println(m.group());
System.out.println(m.start() + "..." + m.end());
}
}
private static void Demo2() {
String str="008.109.090.030";
String reg="0+(\\d+)";//Greedy 数量词
Pattern p=Pattern.compile(reg);
Matcher m=p.matcher(str);
while( m.find() ){
System.out.print(m.group()+"--->");
int len= m.groupCount();
System.out.print(len+"-----");
for(int i=0;i<=1;i++){
System.out.print("group"+"("+i+"):"+m.group(i)+" ");
}
System.out.println(" ");
}
System.out.println("++++++++++++++++++++++++++++++++++++++");
String str1="008.109.090.030";
String reg1="0+(\\d+?)";//Reluctant 数量词
Pattern p1=Pattern.compile(reg1);
Matcher m1=p1.matcher(str1);
while( m1.find() ){
System.out.print(m1.group()+"--->");
int len= m1.groupCount();
System.out.print(len+"-----");
for(int i=0;i<=1;i++){
System.out.print("group"+"("+i+"):"+m1.group(i)+" ");
}
System.out.println(" ");
}
}
}
结果:
008--->1-----group(0):008 group(1):8
09--->1-----group(0):09 group(1):9
090--->1-----group(0):090 group(1):90
030--->1-----group(0):030 group(1):30
++++++++++++++++++++++++++++++++++++++
008--->1-----group(0):008 group(1):8
09--->1-----group(0):09 group(1):9
09--->1-----group(0):09 group(1):9
03--->1-----group(0):03 group(1):3
程序结果分析:
String reg="0+(\\d+)";//Greedy 数量词
008--->1-----group(0):008 group(1):8
09--->1-----group(0):09 group(1):9
90--->1-----group(0):090 group(1):90
030--->1-----group(0):030 group(1):30
这个表达式的匹配规则就是0开头的数字字符串,表达式’\\d‘表示数字匹配,‘+’表示一次或多次匹配前面的字符
++++++++++++++++++++++++++++++++++++++
String reg1="0+(\\d+?)"
008--->1-----group(0):008 group(1):8
09--->1-----group(0):09 group(1):9
09--->1-----group(0):09 group(1):9
03--->1-----group(0):03 group(1):3
表达式中的‘?’表示当此字符紧随任何其他限定符(*、+、?、{n}、{n,}、{n,m})之后时,匹配模式是“非贪心的”。“非贪心的”模式匹配搜索到的、尽可能短的字符串,而默认的“贪心的”模式匹配搜索到的、尽可能长的字符串。例如,在字符串“oooo”中,“o+?”只匹配单个“o”,而“o+”匹配所有“o”,近似于String reg1="0+(\\d)"表达式。