Java字符串支持使用正则表达式进行替换和分隔操作,字符串提供的正则表达式操作是有限的,比如打印正则表达式匹配到的每一个字符串就无法通过字符串提供的方法来实现。Java使用Pattern和Matcher两个类来支持正则表达式功能,字符串提供的正则表达式功能实际也是调用这两个类来实现的。 本文将介绍Pattern和Matcher的使用方法。
Pattern
Pattern用来表示一个编译后的正则表达式,Pattern对象通过compile静态方法创建:
Pattern p = Pattern.compile("cat");
compile方法的参数即为正则表达式,上例中的正则表达式为cat。
Matcher
Matcher对象封装了匹配、替换、遍历等操作。它是通过Pattern对象的matcher方法创建:
Matcher m = p.matcher("one cat two cats in the yard");
matcher方法的参数为输入字符串或待匹配的字符串。
正则表达式功能为什么要用两个对象来实现?
Java把正则表达式功能划分为Pattern和Matcher,这样做的缺点是使用上稍显复杂,优点是多个Matcher可以共享同一个Pattern。Pattern表示编译后的正则表达式,多个Matcher共用一个Pattern时,正则表达式只需编译一次即可,提升了应用程序的性能,下面是多个Matcher对象共用一个Pattern示例:
Pattern p = Pattern.compile("cat");
Matcher m = p.matcher("one cat two cats in the yard");
Matcher m2 = p.matcher("i like my cat");
Matcher m3 = p.matcher("one dog one cat");
匹配
Matcher有三个方法可以进行匹配操作:
- matches
- lookingAt
- find
matches方法使用正则表达式来匹配整个字符串,如果匹配返回true,否则返回false,下面是matches使用示例:
//正则表达式"cat"不能匹配整个字符串"i like my cat"
Pattern p = Pattern.compile("cat");
Matcher m1 = p.matcher("i like my cat");
if (m1.matches())
System.out.println("matches");
else
System.out.println("not matches");
/*程序输出
not matches
*/
//正则表达式"i like my cat"匹配整个字符串"i like my cat"
Pattern p = Pattern.compile("i like my cat");
Matcher m1 = p.matcher("i like my cat");
if (m1.matches())
System.out.println("matches");
else
System.out.println("not matches");
/*程序输出
matches
*/
lookingAt方法使用正则表达式来匹配字符串的开头部分,匹配返回true,不匹配则返回false。它和matches不同之处在于,lookingAt不是必须匹配整个字符串。下面是lookingAt使用示例:
//正则表达式"cat"无法匹配字符串"i like my cat"的开头
Pattern p = Pattern.compile("cat");
Matcher m1 = p.matcher("i like my cat");
if (m1.lookingAt())
System.out.println("matches");
else
System.out.println("not matches");
/*程序输出
not matches
*/
//正则表达式"i"匹配字符串"i like my cat"的开头
Pattern p = Pattern.compile("i");
Matcher m1 = p.matcher("i like my cat");
if (m1.lookingAt())
System.out.println("matches");
else
System.out.println("not matches");
/*程序输出
matches
*/
find方法可以使用正则表达式查找下一个匹配的字符串子串,如果查到匹配的字符串返回true否则返回false。查找到匹配的子串后可以通过start和end()两个方法来获取子串的起始和结束索引。find可以循环调用继续查找下一个匹配的子串,下面是find使用示例:
//使用正则表达式"i"匹配"i like my cat"
Pattern p = Pattern.compile("i");
Matcher m1 = p.matcher("i like my cat");
while (m1.find())
{
System.out.printf("find [%d, %d]\n", m1.start(), m1.end());
}
/*程序输出
find [0, 1]
find [3, 4]
*/
组(Group)
组是正则表达式的一个子集,每个组都有一个编号,通过从左到右计算左括号来进行编号。正则表达式“((A)(B(C))) ”有4个组:
- ((A)(B(C)))
- (A)
- (B(C))
- (C)
组0表示整个正则表达式,除组0外每一个组都被一对括号括住,如果一个正则表达式里面没有括号,则它只有组0即整个表达式。下面是组号的示例程序:
Pattern p = Pattern.compile("([0-9]+)([^0-9]+)");
Matcher m1 = p.matcher("name jack, age 18, weight 70, height 178cm");
if (m1.find())
{
System.out.printf("group0: %s\n", m1.group());
System.out.printf("group1: %s\n", m1.group(1));
System.out.printf("group2: %s\n", m1.group(2));
}
/*程序输出
group0: 18, weight
group1: 18
group2: , weight
*/
上例中组0是整个正则表达式"([0-9]+)([^0-9]+)",组1是第一个左括号括住的内容"([0-9]+)"表示一个数字,组2是第二个左括号括住的内容"([^0-9]+)"表示一个非数字。组0即整个正则表达式匹配到的内容为"18, weight",组1为"18",组2为", weight"。上例中我们只调用find方法一次,所以它只匹配一次。
遍历
使用Matcher对象的find方法查找到字符串时可以通过start和end两个方法获取到匹配字符串的的起止索引,通过起止索引可以获取到匹配到的字符串。还可以通过组号来获取匹配到的字符串,通过组号获取匹配的字符串更加灵活方便,group()方法获取组0,group(int)方法可以指定要获取的组号,示例如下:
//查找所有数字
Pattern p = Pattern.compile("[0-9]+");
Matcher m1 = p.matcher("name jack, age 18, weight 70, height 178cm");
while (m1.find())
{
System.out.printf("find %s\n", m1.group());
}
/*程序输出
find 18
find 70
find 178
*/
替换
Matcher对象支持替换操作的方法有:
- replaceFirst
- replaceAll
- appendReplacement和appendTail
replaceFirst替换匹配到的第一个字符串,replaceAll替换所有匹配到的字符串,示例如下:
//替换第一个数字为0
Pattern p = Pattern.compile("[0-9]+");
Matcher m1 = p.matcher("name jack, age 18, weight 70, height 178cm");
String result = m1.replaceFirst("0");
System.out.println(result);
/*程序输出
name jack, age 0, weight 70, height 178cm
*/
//替换所有数字为0
Pattern p = Pattern.compile("[0-9]+");
Matcher m1 = p.matcher("name jack, age 18, weight 70, height 178cm");
String result = m1.replaceAll("0");
System.out.println(result);
/*程序输出
name jack, age 0, weight 0, height 0cm
*/
appendReplacement和appendTail提供了一种更灵活的方式来执行替换操作,和find()方法一起使用来定制每一个匹配到的字符串的替换方式。例如对每一个匹配到的字符串结尾加"0",示例如下:
//所有字符结尾加0替换
Pattern p = Pattern.compile("[0-9]+");
Matcher m = p.matcher("name jack, age 18, weight 70, height 178cm");
StringBuffer sb = new StringBuffer();
while (m.find()) {
m.appendReplacement(sb, m.group() + "0");
}
m.appendTail(sb);
System.out.println(sb.toString());
/*程序输出
name jack, age 180, weight 700, height 1780cm
*/
appendReplacement有两个参数一个是StringBuffer另一个是替换的字符串,它的执行过程为:
- 把上一次匹配到的字符串和当前匹配到的字符串之间的内容添加到StringBuffer,不包含两个匹配到的字符串。如果是第一次匹配则从整个字符串的的起始位置开始。
- 把替换字符串添加到StringBuffer,即把appendReplacement方法的第二个参数添加到StringBuffer。
appendTail用来把当前匹配到的字符串至整个字符串的结尾之间的内容添加到StringBuffer,不包含匹配到的字符串。
无论是replaceFirst还是replaceAll都无法实现上例中的功能,只有appendReplacement和appendTail可以实现该需求。
最后
使用正则表达式可以实现查找和替换功能,Pattern对象表示编译后的正则表达式,Matcher对象用来执行查找替换功能,Matcher对象常用的方法有:
- matches方法表示正则表达式和整个输入字符串是否匹配。
- lookingAt方法表示正则表达式和输入字符串的开头是否匹配。
- find方法用来查找匹配正则表达式的所有字符串 。
- group方法用来获取匹配到的字符串。
- replaceAll执行全局的替换 。
- replaceFirst只替换第一个匹配的字符串。
- appendReplacement可以定制每一次替换。