正则表达式定义了字符串的模式。
正则表达式可以用来搜索、编辑或处理文本。
正则表达式并不仅限于某一种语言,但是在每种语言中有细微的差别。
正则表达式实例
一个字符串其实就是一个简单的正则表达式,例如 Hello World 正则表达式匹配 “Hello World” 字符串。
.(点号)也是一个正则表达式,它匹配任何一个字符如:“a” 或 “1”。
下表列出了一些正则表达式的实例及描述:
以下实例中使用了正则表达式 .runoob. 用于查找字符串中是否包了 runoob 子串:
import java.util.regex.*;
class RegexExample1{
public static void main(String[] args){
String content = "I am noob " +
"from runoob.com.";
String pattern = ".*runoob.*";
boolean isMatch = Pattern.matches(pattern, content);
System.out.println("字符串中是否包含了 'runoob' 子字符串? " + isMatch);
}
}
实例输出结果为:
字符串中是否包含了 'runoob' 子字符串? true
java.util.regex 包主要包括以下三个类
- Pattern 类:
pattern 对象是一个正则表达式的编译表示。Pattern 类没有公共构造方法。要创建一个 Pattern 对象,你必须首先调用其公共静态编译方法,它返回一个 Pattern 对象。该方法接受一个正则表达式作为它的第一个参数。 - Matcher 类:
Matcher 对象是对输入字符串进行解释和匹配操作的引擎。与Pattern 类一样,Matcher 也没有公共构造方法。你需要调用 Pattern 对象的 matcher 方法来获得一个 Matcher 对象。 - PatternSyntaxException:
PatternSyntaxException 是一个非强制异常类,它表示一个正则表达式模式中的语法错误。
详解Pattern类和Matcher类
java正则表达式通过java.util.regex包下的Pattern类与Matcher类实现.
Pattern类用于创建一个正则表达式,也可以说创建一个匹配模式,它的构造方法是私有的,不可以直接创建,但可以通过Pattern.complie(String regex)简单工厂方法创建一个正则表达式,
Java代码示例:
Pattern p=Pattern.compile("\\w+");
p.pattern();//返回 \w+
pattern() 返回正则表达式的字符串形式,其实就是返回Pattern.complile(String regex)的regex参数
Pattern.split(CharSequence input)
Pattern有一个split(CharSequence input)方法,用于分隔字符串,并返回一个String[],
Java代码示例:
Pattern p=Pattern.compile("\\d+");
String[] str=p.split("我的QQ是:456456我的电话是:0532214我的邮箱是:aaa@aaa.com");
结果:str[0]=“我的QQ是:” str[1]=“我的电话是:” str[2]=“我的邮箱是:aaa@aaa.com”
Pattern.matcher(String regex,CharSequence input)
Pattern.matcher(String regex,CharSequence input)是一个静态方法,用于快速匹配字符串,该方法适合用于只匹配一次,且匹配全部字符串.
Java代码示例:
Pattern.matches("\\d+","2223");//返回true
Pattern.matches("\\d+","2223aa");//返回false,需要匹配到所有字符串才能返回true,这里aa不能匹配到
Pattern.matches("\\d+","22bb23");//返回false,需要匹配到所有字符串才能返回true,这里bb不能匹配到
Pattern.matcher(CharSequence input)
说了这么多,终于轮到Matcher类登场了,Pattern.matcher(CharSequence input)返回一个Matcher对象.
Matcher类的构造方法也是私有的,不能随意创建,只能通过Pattern.matcher(CharSequence input)方法得到该类的实例.
Pattern类只能做一些简单的匹配操作,要想得到更强更便捷的正则匹配操作,那就需要将Pattern与Matcher一起合作.Matcher类提供了对正则表达式的分组支持,以及对正则表达式的多次匹配支持.
Java代码示例:
Pattern p=Pattern.compile("\\d+");
Matcher m=p.matcher("22bb23");
m.pattern();//返回p 也就是返回该Matcher对象是由哪个Pattern对象的创建的
Matcher.matches()/ Matcher.lookingAt()/ Matcher.find()
Matcher类提供三个匹配操作方法,三个方法均返回boolean类型,当匹配到时返回true,没匹配到则返回false
matches()对整个字符串进行匹配,只有整个字符串都匹配了才返回true
Java代码示例:
Pattern p=Pattern.compile("\\d+");
Matcher m=p.matcher("22bb23");
m.matches();//返回false,因为bb不能被\d+匹配,导致整个字符串匹配未成功.
Matcher m2=p.matcher("2223");
m2.matches();//返回true,因为\d+匹配到了整个字符串
我们现在回头看一下Pattern.matcher(String regex,CharSequence input),它与下面这段代码等价 Pattern.compile(regex).matcher(input).matches()
lookingAt()对前面的字符串进行匹配,只有匹配到的字符串在最前面才返回true
Java代码示例:
Pattern p=Pattern.compile("\\d+");
Matcher m=p.matcher("22bb23");
m.lookingAt();//返回true,因为\d+匹配到了前面的22
Matcher m2=p.matcher("aa2223");
m2.lookingAt();//返回false,因为\d+不能匹配前面的aa
find()对字符串进行匹配,匹配到的字符串可以在任何位置.
Java代码示例:
Pattern p=Pattern.compile("\\d+");
Matcher m=p.matcher("22bb23");
m.find();//返回true
Matcher m2=p.matcher("aa2223");
m2.find();//返回true
Matcher m3=p.matcher("aa2223bb");
m3.find();//返回true
Matcher m4=p.matcher("aabb");
m4.find();//返回false
Mathcer.start()/ Matcher.end()/ Matcher.group()
当使用matches(),lookingAt(),find()执行匹配操作后,就可以利用以上三个方法得到更详细的信息.
start()返回匹配到的子字符串在字符串中的索引位置.
end()返回匹配到的子字符串的最后一个字符在字符串中的索引位置.
group()返回匹配到的子字符串
Java代码示例:
Pattern p=Pattern.compile("\\d+");
Matcher m=p.matcher("aaa2223bb");
m.find();//匹配2223
m.start();//返回3
m.end();//返回7,返回的是2223后的索引号
m.group();//返回2223
Mathcer m2=m.matcher("2223bb");
m.lookingAt(); //匹配2223
m.start(); //返回0,由于lookingAt()只能匹配前面的字符串,所以当使用lookingAt()匹配时,start()方法总是返回0
m.end(); //返回4
m.group(); //返回2223
Matcher m3=m.matcher("2223bb");
m.matches(); //匹配整个字符串
m.start(); //返回0,原因相信大家也清楚了
m.end(); //返回6,原因相信大家也清楚了,因为matches()需要匹配所有字符串
m.group(); //返回2223bb
说了这么多,相信大家都明白了以上几个方法的使用,该说说正则表达式的分组在java中是怎么使用的.
start(),end(),group()均有一个重载方法它们是start(int i),end(int i),group(int i)专用于分组操作,Mathcer类还有一个groupCount()用于返回有多少组.
Java代码示例:
Pattern p=Pattern.compile("([a-z]+)(\\d+)");
Matcher m=p.matcher("aaa2223bb");
m.find(); //匹配aaa2223
m.groupCount(); //返回2,因为有2组
m.start(1); //返回0 返回第一组匹配到的子字符串在字符串中的索引号
m.start(2); //返回3
m.end(1); //返回3 返回第一组匹配到的子字符串的最后一个字符在字符串中的索引位置.
m.end(2); //返回7
m.group(1); //返回aaa,返回第一组匹配到的子字符串
m.group(2); //返回2223,返回第二组匹配到的子字符串
现在我们使用一下稍微高级点的正则匹配操作,例如有一段文本,里面有很多数字,而且这些数字是分开的,我们现在要将文本中所有数字都取出来,利用java的正则操作是那么的简单.
Java代码示例:
Pattern p=Pattern.compile("\\d+");
Matcher m=p.matcher("我的QQ是:456456 我的电话是:0532214 我的邮箱是:aaa123@aaa.com");
while(m.find()) {
System.out.println(m.group());
}
输出:
456456
0532214
123
如将以上while()循环替换成
while(m.find()) {
System.out.println(m.group());
System.out.print("start:"+m.start());
System.out.println(" end:"+m.end());
}
则输出:
456456
start:6 end:12
0532214
start:19 end:26
123
start:36 end:39
现在大家应该知道,每次执行匹配操作后start(),end(),group()三个方法的值都会改变,改变成匹配到的子字符串的信息,以及它们的重载方法,也会改变成相应的信息.
注意:只有当匹配操作成功,才可以使用start(),end(),group()三个方法,否则会抛出java.lang.IllegalStateException,也就是当matches(),lookingAt(),find()其中任意一个方法返回true时,才可以使用.
捕获组
捕获组是把多个字符当一个单独单元进行处理的方法,它通过对括号内的字符分组来创建。
例如,正则表达式 (dog) 创建了单一分组,组里包含"d",“o”,和"g"。
捕获组是通过从左至右计算其开括号来编号。例如,在表达式((A)(B(C))),有四个这样的组:
- ((A)(B( C )))
- (A)
- (B( C ))
- ( C )
可以通过调用 matcher 对象的 groupCount 方法来查看表达式有多少个分组。groupCount 方法返回一个 int 值,表示matcher对象当前有多个捕获组。
还有一个特殊的组(group(0)),它总是代表整个表达式。该组不包括在 groupCount 的返回值中。
实例
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexMatches
{
public static void main( String[] args ){
// 按指定模式在字符串查找
String line = "This order was placed for QT3000! OK?";
String pattern = "(\\D*)(\\d+)(.*)";
// 创建 Pattern 对象
Pattern r = Pattern.compile(pattern);
// 现在创建 matcher 对象
Matcher m = r.matcher(line);
if (m.find( )) {
System.out.println("Found value: " + m.group(0) );
System.out.println("Found value: " + m.group(1) );
System.out.println("Found value: " + m.group(2) );
System.out.println("Found value: " + m.group(3) );
} else {
System.out.println("NO MATCH");
}
}
}
以上实例编译运行结果如下:
Found value: This order was placed for QT3000! OK?
Found value: This order was placed for QT
Found value: 3000
Found value: ! OK?
正则表达式语法
在其他语言中,\ 表示:我想要在正则表达式中插入一个普通的(字面上的)反斜杠,请不要给它任何特殊的意义。
在 Java 中,\ 表示:我要插入一个正则表达式的反斜线,所以其后的字符具有特殊的意义。
所以,在其他的语言中(如Perl),一个反斜杠 \ 就足以具有转义的作用,而在 Java 中正则表达式中则需要有两个反斜杠才能被解析为其他语言中的转义作用。也可以简单的理解在 Java 的正则表达式中,两个 \ 代表其他语言中的一个 \,这也就是为什么表示一位数字的正则表达式是 \d,而表示一个普通的反斜杠是 \\。
根据 Java Language Specification 的要求,Java 源代码的字符串中的反斜线被解释为 Unicode 转义或其他字符转义。因此必须在字符串字面值中使用两个反斜线,表示正则表达式受到保护,不被 Java 字节码编译器解释。例如,当解释为正则表达式时,字符串字面值 “\b” 与单个退格字符匹配,而 “\b” 与单词边界匹配。字符串字面值 “(hello)” 是非法的,将导致编译时错误;要与字符串 (hello) 匹配,必须使用字符串字面值 “\\(hello\\)
”。
Matcher 类的方法
索引方法
索引方法提供了有用的索引值,精确表明输入字符串中在哪能找到匹配:
查找方法
查找方法用来检查输入字符串并返回一个布尔值,表示是否找到该模式:
替换方法
替换方法是替换输入字符串里文本的方法:
start 和 end 方法
下面是一个对单词 “cat” 出现在输入字符串中出现次数进行计数的例子:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexMatches
{
private static final String REGEX = "\\bcat\\b";
private static final String INPUT =
"cat cat cat cattie cat";
public static void main( String[] args ){
Pattern p = Pattern.compile(REGEX);
Matcher m = p.matcher(INPUT); // 获取 matcher 对象
int count = 0;
while(m.find()) {
count++;
System.out.println("Match number "+count);
System.out.println("start(): "+m.start());
System.out.println("end(): "+m.end());
}
}
}
以上实例编译运行结果如下:
Match number 1
start(): 0
end(): 3
Match number 2
start(): 4
end(): 7
Match number 3
start(): 8
end(): 11
Match number 4
start(): 19
end(): 22
可以看到这个例子是使用单词边界,以确保字母 “c” “a” “t” 并非仅是一个较长的词的子串。它也提供了一些关于输入字符串中匹配发生位置的有用信息。
Start 方法返回在以前的匹配操作期间,由给定组所捕获的子序列的初始索引,end 方法最后一个匹配字符的索引加 1。
matches 和 lookingAt 方法
matches 和 lookingAt 方法都用来尝试匹配一个输入序列模式。它们的不同是 matches 要求整个序列都匹配,而lookingAt 不要求。
lookingAt 方法虽然不需要整句都匹配,但是需要从第一个字符开始匹配。
这两个方法经常在输入字符串的开始使用。
我们通过下面这个例子,来解释这个功能:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexMatches
{
private static final String REGEX = "foo";
private static final String INPUT = "fooooooooooooooooo";
private static final String INPUT2 = "ooooofoooooooooooo";
private static Pattern pattern;
private static Matcher matcher;
private static Matcher matcher2;
public static void main( String[] args ){
pattern = Pattern.compile(REGEX);
matcher = pattern.matcher(INPUT);
matcher2 = pattern.matcher(INPUT2);
System.out.println("Current REGEX is: "+REGEX);
System.out.println("Current INPUT is: "+INPUT);
System.out.println("Current INPUT2 is: "+INPUT2);
System.out.println("lookingAt(): "+matcher.lookingAt());
System.out.println("matches(): "+matcher.matches());
System.out.println("lookingAt(): "+matcher2.lookingAt());
}
}
以上实例编译运行结果如下:
Current REGEX is: foo
Current INPUT is: fooooooooooooooooo
Current INPUT2 is: ooooofoooooooooooo
lookingAt(): true
matches(): false
lookingAt(): false
replaceFirst 和 replaceAll 方法
replaceFirst 和 replaceAll 方法用来替换匹配正则表达式的文本。不同的是,replaceFirst 替换首次匹配,replaceAll 替换所有匹配。
下面的例子来解释这个功能:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexMatches
{
private static String REGEX = "dog";
private static String INPUT = "The dog says meow. " +
"All dogs say meow.";
private static String REPLACE = "cat";
public static void main(String[] args) {
Pattern p = Pattern.compile(REGEX);
// get a matcher object
Matcher m = p.matcher(INPUT);
INPUT = m.replaceAll(REPLACE);
System.out.println(INPUT);
}
}
以上实例编译运行结果如下:
The cat says meow. All cats say meow.
appendReplacement 和 appendTail 方法
Matcher 类也提供了appendReplacement 和 appendTail 方法用于文本替换:
看下面的例子来解释这个功能:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexMatches
{
private static String REGEX = "a*b";
private static String INPUT = "aabfooaabfooabfoobkkk";
private static String REPLACE = "-";
public static void main(String[] args) {
Pattern p = Pattern.compile(REGEX);
// 获取 matcher 对象
Matcher m = p.matcher(INPUT);
StringBuffer sb = new StringBuffer();
while(m.find()){
m.appendReplacement(sb,REPLACE);
}
m.appendTail(sb);
System.out.println(sb.toString());
}
}
以上实例编译运行结果如下:
-foo-foo-foo-kkk
PatternSyntaxException 类的方法
PatternSyntaxException 是一个非强制异常类,它指示一个正则表达式模式中的语法错误。
PatternSyntaxException 类提供了下面的方法来帮助我们查看发生了什么错误。
java.util.regex.PatternSyntaxException
public static void main(String[] args) throws Exception {
String test = "-1+-2.3-2+-2";
test = test.replaceAll("+-", "-");
System.out.println(test);
}
该代码段是想把表达式中的所有"±"都替换为"-",却出现以下异常:
因为正则表达式中"+“为特殊符号,是量词,表示{1,},因此,要匹配”+“这个字符,需要转义”+",java中要"\+"
程序改为:
public static void main(String[] args) throws Exception {
String test = "-1+-2.3-2+-2";
test = test.replaceAll("\\+-", "-");
System.out.println(test);
}
结果:
此外,此类特殊符号还有:? * () [] {} ^ $等等