概述
正则表达式能够解决各种字符串处理的问题:
匹配
,
选择
,
编辑
以及
验证
。正则表达式是一种强大灵活的文本处理工具,在很多语言中都支持正则表达式。本文主要介绍的是java的正则表达式的使用。
基础
在正则表达式中我们要表示一个数字,可以用\d表示。但是java对\的处理和其他语言不同。其他语言中\表示 要在正则表达式中插入一个字面上的反斜线,没有特殊含义,而在java中,\表示 我要在正则表达式中插入一个反斜线,其后面的字符具有特殊的含义。 所以java中,你要表示数字就是\d,要表示一个字面上的反斜线就是\\。当然换行和制表符除外:\n\t。
以下是是特殊字符代表的含义。

例子:
public class Test {
public static void main(String[] args) {
//判断数字
System.out.println("asda".matches("\\d+"));
//?是存在一个或零个之前的符号
System.out.println("2321".matches("-?\\d+"));
System.out.println("+2321".matches("-?\\d+"));
}
}
/*
false
true
false
*/
Pattern 类
上面的例子是String自带的正则验证,还有一个更强大的替换工具,而且具有更佳的性能。
那就是
java.util.regex.Pattern
和
java.util.regex.Matcher
,String内部也是使用了这个类来实现
第一步,通过正则表达式创建模式对象 Pattern。
第二步,通过模式对象 Pattern,根据指定字符串创建匹配对象 Matcher。
第三步,通过匹配对象 Matcher,根据正则表达式操作字符串。
例子1:
匹配模式
有三种匹配方式,叫做贪婪型,非贪婪型,占有型。对于这三种匹配模式也有叫:
“最大匹配Greedy”``“最小匹配Reluctant”``“完全匹配Possessive”
。
贪婪 | 勉强 | 侵占 | 含义 |
---|---|---|---|
X? | X?? | X?+ | 匹配 X 零次或一次 |
X* | X*? | X*+ | 匹配 X 零次或多次 |
X+ | X+? | X++ | 匹配 X 一次或多次 |
X{n} | X{n}? | X{n}+ | 匹配 X n 次(这个应该不存在这几种模式,就是固定匹配n个) |
X{n,} | X{n,}? | X{n,}+ | 匹配 X 至少 n 次 |
X{n,m} | X{n,m}? | X{n,m}+ | 匹配 X 至少 n 次,但不多于 m 次 |
从上表可以看出贪婪型是默认的匹配方式,勉强型是在贪婪型后面加上?,占有型是在贪婪型后面加上+。
Greediness(贪婪型):也叫最大匹配
例如你要用 “<.+>”去匹配“aaavaabb”,也许你所期待的结果是想匹配 “”,但是实际结果却会匹配到“aava”。这是为什么呢?下面我们跟踪下最大匹配的匹 配过程。
①“<”匹配字符串的“<”。
②“.+”匹配字符串的“tr>aavaab”,在进行最大匹配时,它把两个 “>”都匹配了,它匹配了所有字符,直到文本的最后字符“b”③这时,发现不能成功匹配“>”,开始按原路回退,用“a”与“>”匹 配,直到“ab”前面的“>”匹配成功。
Reluctant(Laziness)(勉强型):最小匹配
最小匹配意味者,.+? 匹配一个字符后,马上试一试>的匹配可能,失败了,则.+?再匹配一个字符,再马上试一试>的匹配可能。JDK文档中Greedy 和Reluctant,它是以eat一口来隐喻的,所以翻译成贪吃和(勉强的)厌食最贴切了。不过我喜欢最大匹配、最小匹配的说法。
Possessive(占有型):完全匹配
与最大匹配不同,还有一种匹配形式:X?+、X*+、X++、X{n}+、X{n,}+、X{n,m}+等,成为完全匹配。它和最大匹配一样,一直匹配所有的字符,直到文本的最后,但它不原路返回。
这个不大好理解,有一个例子摘自http://bbs.csdn.net/topics/390269371比较形象:
字符串为aaa,正则表达式为[a]+,这是一个贪婪的匹配,直接返回aaa。但是如果是占有型的,正则为[a]+a,返回结果是false,是空。
如果a*a,是匹配优先的,也就是说先匹配,如果正则的后续部分不能再匹配,就回溯,在这个例子中,匹配字符串aaa的时候,首先a匹配到最后一个,然后发现正则后面还有一个a没法匹配,就会将a*回溯到字符串的中间一个a,这时候正则中的最后一个a与字符串的最后一个a正好匹配,匹配结束。
如果正则是a*+a,+是占有优先,也就是说+前面的字符会尽可能匹配,匹配了的就不会再回溯,不会让回去了,即所谓占有。如果字符串是aaa,那么这个例子中匹配过程就是a*+匹配了字符串的三个a,正则中的最后一个a不会再被匹配,因为a*+不会回溯。
来源:http://blog.csdn.net/xh16319/article/details/27498287
例子:(特殊提醒在正则表达式中[,左中括号是特殊字符,所以要加\,]右中括号不是特殊字符所以不用加\):
String str = "This is [google][1],this is [apple][2],and this is [ms][3]";
//贪婪匹配
Pattern pattern1 = Pattern.compile("\\[.*]");
Matcher matcher1 = pattern1.matcher(str);
while (matcher1.find()) {
System.out.println(matcher1.group());
}
System.out.println("----------");
//非贪婪匹配
Pattern pattern2 = Pattern.compile("\\[.*?]");
Matcher matcher2 = pattern2.matcher(str);
while (matcher2.find()) {
System.out.println(matcher2.group());
}
System.out.println("----------");
//独占匹配
String str1 = "[google1]";
//下面两种会有不同的而结果,因为.*是占有的他先会把所有符合的匹配光,所以第一个匹配时str1中的]会被匹配在.*中,当匹配后面]的时候没有字符给他匹配了。
//Pattern pattern3 = Pattern.compile("\\[.*+]");
Pattern pattern3 = Pattern.compile("\\[.*+");
Matcher matcher3 = pattern3.matcher(str1);
while (matcher3.find()) {
System.out.println(matcher3.group());
}
由于三种方式匹配的规则不同,有着不同的计算量,所以引发的问题:一个有正则表达式引发的血案 http://zhuanlan.51cto.com/art/201708/549051.htm
分组和标签
正则表达式还有一个分组的功能。(a)((b)(c))当用这个当做正则表达是匹配的时候,每个括号都可以当做一个组。组号为从左到右
(
左括号出现的个数,0代表全部。group()或者group(0)代表全部,group(1)为(a), group(2)为((b)(c)),group(3)为(b),group(3)为(c)。
比如:
public static void test3() {
String str = "1111bbbbbb ccccc22222";
//贪婪匹配
Pattern pattern1 = Pattern.compile("(\\d+)([a-zA-Z]+)(\\s+)([a-zA-Z]+)(\\d+)");
Matcher matcher1 = pattern1.matcher(str);
while (matcher1.find()) {
System.out.println("group():" + matcher1.group());
System.out.println("group(0):" + matcher1.group());
System.out.println("group(1):" + matcher1.group());
System.out.println("group(2):" + matcher1.group());
System.out.println("group(3):" + matcher1.group());
System.out.println("group(4):" + matcher1.group());
}
}
还通过?<name>对组进行命名。
//对组1和组2进行命名
public static void test4() {
String str = "1111bbbbbb ccccc22222";
//贪婪匹配
Pattern pattern1 = Pattern.compile("(?<name1>\\d+)(?<name2>[a-zA-Z]+)(\\s+)([a-zA-Z]+)(\\d+)");
Matcher matcher1 = pattern1.matcher(str);
while (matcher1.find()) {
System.out.println("group():" + matcher1.group("name1"));
System.out.println("group(0):" + matcher1.group("name2"));
}
}
在线工具以及常用的正在表达式
参考资料:
- 《java编程思想》
- 《Java编程思想第四版》笔记—13章 字符串