Java中的正则表达式匹配功能
java语言中的正则表达式匹配功能
java语言中的正则表达式匹配功能主要是通过java.util.regex.Matcher类和以下这些方法实现的。
- find():在一个字符串里寻找一个给定模式的匹配。
- lookingAt(): 用一个给定的模式去尝试匹配一个字符串的开头。
- matches():用一个给定的模式去尝试匹配一个完整的字符串。
- replaceAll():进行替换操作,对所有的匹配都进行替换。
- replaceFirst():进行替换操作,只对第一个匹配进行替换。
matcher类还提供了几个能够让程序员对特定操作做出更细致调控的方法。此外,java.util.regex.pattern类也提供了几个简单易用的包装器方法。 - compile():把一个正则表达式编译成一个模式。
- flags():返回某给定模式的匹配标志。
- matches():在功能上等价于刚才介绍的matches()方法。Pattern类的构造方法是私有的,所以我们使用
Pattern p = Pattern.compile("a*b")
进行实例化;Matcher类的实例化依赖Pattern类的对象Matcher m = p.matcher("aaaaab")
; - pattern():把一个模式还原为一个正则表达式。
- split():把一个字符串分为子字符串。
在实际的开发中,为了方便我们很少直接使用Pattern类或Matcher类,而是使用String类下的方法
- 验证:
boolean matches(String regex)
- 拆分:
String[] split(String regex)
- 替换:
String replaceAll(String regex, String replacement)
注意事项
Sun公司发布的Java正则表达式支持与Perl语言基本兼容,但要注意以下几点。
- 要想使用正则表达式,必须先用
import java.util.regex.*
语句导入正则表达式组件(这条语句将导入一个完整的软件包。如果你只需要用到其中的一部分功能,请用相应的软件包名字替换掉这条语句里的*)。 - 不支持嵌入条件。
- 不支持使用\E、\l、\L、\u和\U进行字母大小写转换。
- 不支持使用\b匹配退格符。
- 不支持\z。
java中正则表达式常用的语法
字符的取值范围
- [abc] : 表示可能是a,可能是b,也可能是c。
- [^abc]: 表示不是a,b,c中的任意一个
- [a-zA-Z]: 表示是英文字母
- [0-9]:表示是数字
简洁的字符表示
- .:匹配任意的字符
- \d:表示数字
- \D:表示非数字
- \s:表示由空格组成,[ \t\n\r\x\f]
- \S:表示由非空字符组成,[^\s]
- \w:表示字母、数字、下划线,[a-zA-Z0-9_]
- \W:表示不是由字母、数字、下划线组成
- \b:匹配一个字边界,即字与空格间的位置。例如,"er\b"匹配"never"中的"er",但不匹配"verb"中的"er"。
- \B:非字边界匹配。"er\B"匹配"verb"中的"er",但不匹配"never"中的"er"。
数量表达式
- ?: 表示出现0次或1次
- +: 表示出现1次或多次
- *: 表示出现0次、1次或多次
- {n}:表示出现n次
- {n,m}:表示出现n~m次
- {n,}:表示出现n次或n次以上
- ?:当此字符紧随任何其他限定符(*、+、?、{n}、{n,}、{n,m})之后时,匹配模式是"非贪心的"。"非贪心的"模式匹配搜索到的、尽可能短的字符串,而默认的"贪心的"模式匹配搜索到的、尽可能长的字符串。例如,在字符串"oooo"中,"o+?"只匹配单个"o",而"o+"匹配所有"o"。
注意:*, +, {n,}都是常用的贪婪型元字符,在匹配时它们会尽可能地从一段文本的开头一直匹配到这段文本的末尾,而不是从这段文本的开头匹配到碰到第一个匹配时为止。
例如:
文本:
living in <B>AK</B> and <B>HI</B>.
正则表达式:
<Bb>.*<Bb>
结果:
living in <B>AK</B> and <B>HI</B>.
这时需要使用相应的懒惰型元字符,防止过度匹配,在贪婪型元字符后加上一个?后缀即可,即*?、+?、{n,}?等。
例如:
文本:
living in <B>AK</B> and <B>HI</B>.
正则表达式:
<Bb>.*?<Bb>
结果:
living in <B>AK</B> and <B>HI</B>.
逻辑表达式
- XY: 表示X后面跟着Y,这里X和Y分别是正则表达式的一部分
- X|Y:表示X或Y,比如"food|f"匹配的是foo(d或f),而"(food)|f"匹配的是food或f
- (X):子表达式,将X看做是一个整体
多用途元字符
- *:只有当它出现在一个字符集合里(被放在[和]之间)并紧跟在左方括号[的后面时,它才能发挥“求非”作用。如果是在一个字符集合的外面并位于一个模式的开头,^将匹配字符串的开头。
例如:[^abc]: 表示不是a,b,c中的任意一个;
^\s*<\?xml.*\?>:匹配一个<?xml>标签内容,并且该内容出现在字符串的开头
相应的,$匹配字符串的结尾,如\s*$匹配一个字符串结尾处的零个或多个空白字符
回溯引用匹配:前后一致匹配
例如:
文本:
<H1>ColdFusion</H1>
<H2>ColdFusion</H2>
<H2>This is not valid HTML</H3>
正则表达式:
<[hH][1-6]>.*?</[hH][1-6]>
结果:
<H1>ColdFusion</H1>
<H2>ColdFusion</H2>
<H2>This is not valid HTML</H3>
分析:
在这个例子里,原始文本里有一个标题是以<H2>开头、以<H3>结束的。这显然是一个不合法的标题,但它与我们所使用的模式匹配上了。出现这种情况的根源是这个模式的第2部分(用来匹配结束标签的那个部分)对这个模式的第1部分(用来匹配开始标签的那个部分)毫无所知。要想彻底解决这个问题,就只能求助于回溯引用。
再如:
文本:
This is a block of of text, several words here are are repeated
正则表达式:
[ ]+(\w+)[ ]+\1
结果:
This is a block of of text, several words here are are repeated
分析:
[ ]+匹配一个或多个空格,\w+匹配一个或多个字母数字字符,[ ]+匹配随后的空格。注意,\w+是括在括号里的,它是一个子表达式。这个子表达式不是用来进行重复匹配的,这里根本不涉及重复匹配的问题。这个子表达式只是把整个模式的一部分单独划分出来以便在后面引用。这个模式的最后一部分是\1;这是一个回溯引用,而它引用的正是前面划分出来的那个子表达式:当(\w+)匹配到单词of的时候,\1也匹配单词of;当(\w+)匹配到单词and的时候,\1也匹配单词and。可以把回溯引用想像成变量
所以,上一个例子的正则表达应该写成:
<[hH]([1-6])>.*?</[hH]\1>
结果:
<H1>ColdFusion</H1>
<H2>ColdFusion</H2>
<H2>This is not valid HTML</H3>
分析:
<[hH]([1-6])>匹配任何一级标题的开始标签,但我们这次用(和)把[1-6]括了起来,使它成为了一个子表达式。这样一来,我们就可以在用来匹配标题结束标签的</[hH]\1>用\1来引用这个子表达式了。子表达式([1-6])匹配数字1~6, \1只匹配与之相同的数字。这样一来,原始文本里的<H2>This is notvalid HTML就不会被匹配到了。
回溯引用在替换操作中的应用
如下例:
文本:
Hello, ben@forta.com is my email address!
正则表达式:
\w+[\w.]*@[\w.]+\.\w+
结果:
Hello, ben@forta.com is my email address!
分析:
这个模式可以把原始文本里的电子邮件地址查找出来。现在,假设你需要把原始文本里的电子邮件地址全都转换为可点击的链接,你该怎么办?在HTML文档里,你需要使用
<A HREF="maito:user@address.com">user@address.com</A>这样的语法来创建一个可点击的电子邮件地址。能不能用一个正则表达式把一个电子邮件地址转换为这种可点击的地址格式呢?当然能,而且非常容易——但前提是你得使用回溯引用,如下所示:
文本:
Hello, ben@forta.com is my email address!
正则表达式:
(\w+[\w.]*@[\w.]+\.\w+)
替换:
<A HREF="mailto:$1">$1</A>
Java代码:
public static void main(String[] args) {
// 1. 回溯引用在替换操作中的应用
String str = "Hello, ben@forta.com is my email address!";
String regex = "(\w+[\w.]*@[\w.]+\.\w+)";
Pattern pat = Pattern.compile(regex); //实例化Pattern对象
Matcher mat = pat.matcher(str); //实例化Matcher对象
while(mat.find()) {
System.out.println(mat.replaceAll("<A HREF=\"mailto:$1\">$1</A>"));
}
}
结果:
转义字符
在其他语言中,\\
表示:我想要在正则表达式中插入一个普通的(字面上的)反斜杠,请不要给它任何特殊的意义。
在 Java 中,\\
表示:我要插入一个正则表达式的反斜线,所以其后的字符具有特殊的意义。
所以,在其他的语言中(如 Perl),一个反斜杠 \
就足以具有转义的作用,而在 Java 中正则表达式中则需要有两个反斜杠才能被解析为其他语言中的转义作用。也可以简单的理解在 Java 的正则表达式中,两个 \\
代表其他语言中的一个 \
,这也就是为什么表示一位数字的正则表达式是 \\d
,而表示一个普通的反斜杠是 \\
。
System.out.print("\\"); // 输出为 \
System.out.print("\\\\"); // 输出为 \\
了解更多请转到 RUNOOB.COM