013 014 015 016 017 018 019 020
import java.util.regex.Pattern; import java.util.regex.Matcher;
public class RegexDemo {
private static String REGEX = \
private static String INPUT = \ private static String REPLACE = \
public static void main(String[] args) { Pattern p = Pattern.compile(REGEX);
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-
9.5 在 java.lang.String 中等价的 Matcher 方法返回目录
为了使用方便,String 类看上去还不错地模仿了 Matcher 的两个方法:
public String replaceFirst(String regex, String replacement):使用给定的替换字符串替换该字符串中匹配了给定正则表达式的第一个子字符串。调用 str.replaceFirst(regex, repl)方法与使用 Pattern.compile(regex).matcher(str).replaceFirst(repl)产生的结果是完全相同的。
public String replaceAll(String regex, String replacement):使用给定的替换字符串替换该字符串中匹配了给定正则表达式的每一个子字符串。调用 str.replaceAll(regex, repl)方法与使用 Pattern.compile(regex).matcher(str).replaceAll(repl)产生的结果是完全相同的。 10 PatternSyntaxException 类的方法返回目录
PatternSyntaxException 是未检查异常,指示正则表达式模式中的语法错误。PatternSyntaxException 类提供了下面的一些方法,用于确定在什么地方发生了错误: public String getDescription():获得错误描述。 public int getIndex():获得错误索引。
public String getPattern():获得字符串形式的错误正则表达式。
public String getMessage():获得一个多行的字符串,包括语法错误和错误的索引、错误的正则表达式模式,以及模式内可视化的索引指示。
下面的源代码(RegexTestHarness2.java[10])更新了测试用具,用于检查不正确的正则表达式:
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034
035 036 037 038 039 040 041 042
import java.io.Console;
import java.util.regex.Pattern; import java.util.regex.Matcher;
import java.util.regex.PatternSyntaxException;
public class RegexTestHarness2 {
public static void main(String[] args){ Pattern pattern = null; Matcher matcher = null;
Console console = System.console(); if (console == null) {
System.err.println(\ System.exit(1); }
while (true) { try {
pattern = Pattern.compile(console.readLine(\your regex: \
matcher = pattern.matcher(console.readLine(\input string to search: \
} catch (PatternSyntaxException pse){
console.format(\expression!%n\
console.format(\pse.getPattern());
console.format(\pse.getDescription());
console.format(\pse.getMessage());
console.format(\index is: %s%n\pse.getIndex()); System.exit(0); }
boolean found = false; while (matcher.find()) { console.format(\found the text \\\starting at \+ \ matcher.group(), matcher.start(), matcher.end()
);
found = true; }
if (!found){
console.format(\ } } } }
运行该测试,输入?i)foo作为正则表达式。这是个臆想出来的错误,程序员在使用内嵌标志表达式(?i)时忘记输入左括号了。这样做会产生下面的结果:
Enter your regex: ?i)
There is a problem with the regular expression! The pattern in question is: ?i)
The description is: Dangling meta character '?'
The message is: Dangling meta character '?' near index 0 ?i) ^
The index is: 0
从这个输出中,可以看出在索引 0 处的元字符(?)附近有语法错误。缺少左括号是导致这个错误的
最魁祸首。
11 更多的资源返回目录
现在已经结束了正则表达式的课程,你也许会发现,主要引用了 Pattern、Matcher 和 PatternSyntaxException 类的 API 文档。
构建正则表达式更详细地描述,推荐阅读 Jeffrey E.F.Friedl 的Mastering Regular Expressions[11]。 12 问题和练习返回目录 〖问题〗
1. 在 java.util.regex 包中有哪三个公共的类?描述一下它们的作用。
2. 考虑一下字符串“foo”,它的开始索引是多少?结束索引是多少?解释一下这些编号的意思。 3. 普通字符和元字符有什么不同?各给出它们的一个例子。 4. 如何把元字符表现成像普通字符那样?
5. 附有方括号的字符集称为什么?它有什么作用?
6. 这里是三个预定义的字符类:\\d、\\s和\\w。描述一下它们各表示什么?并使用方括号的形式将它们重写。
7. 对于\\d、\\s和\\w,写出两个简单的表达式,匹配它们相反的字符集。
8. 思考正则表达式(dog){3},识别一下其中的两个子表达式。这个表达式会匹配什么字符串? 〖练习〗
1. 使用反向引用写一个表达式,用于匹配一个人的名字,假设这个人的 first 名字与 last 名字是相同的。 【问题答案】
1. 问:在 java.util.regex 包中有哪三个公共的类?描述一下它们的作用。 答:
? ? ?
编译后的 Pattern 实例表示正则表达式。
Matcher 实例是解析模式和靠着输入的字符串完成匹配操作的引擎。
PatternSyntaxException 定义一个未检查异常,指示正则表达式中的语法错误。
2. 问:考虑一下字符串“foo”,它的开始索引是多少?结束索引是多少?解释一下这些编号的意思。 答:字符串中的每一个字符位于其自身的单元格中。索引位置在两个单元格之间。字符串“foo”开始于索引 0,结束于索引 3,即便是这些字符仅占用了 0、1 和 2 号单元格。 3. 问:普通字符和元字符有什么不同?各给出它们的一个例子。
答:正则表达式中的普通字符匹配其本身。元字符是一个特殊的字符,会影响被匹配模式的方式。字母A是一个普通字符。标点符号.是一个元字符,其匹配任意的单字符。 4. 问:如何把元字符表现成像普通字符那样? 答:有两种方法:
在元字符前加上反斜线(\\);
把元字符置于\\Q(开始)\\E(结束)的引用表达式中。
5. 问:附有方括号的字符集称为什么?它有什么作用?
答:是一个字符类。通过方括号间的表达式,匹配指定字符类中的任意一个字符。
6. 问:这里是三个预定义的字符类:\\d、\\s和\\w。描述一下它们各表示什么?并使用方括号的形式将它们重写。
答:\\d 匹配任意数字[0-9]
? ?
\\s 匹配任意空白字符[ \\t\\n-x0B\\f\\r] \\w 匹配任意单词字符[a-zA-Z_0-9]
7. 问:对于\\d、\\s和\\w,写出两个简单的表达式,匹配它们相反的字符集。 答:\\d \\D [^\\d] \\s \\S [^\\s] \\w \\W [^\\w]
8. 问:思考正则表达式(dog){3},识别一下其中的两个子表达式。这个表达式会匹配什么字符串? 答:表达式由捕获组(dog)和接着的贪婪量词{3}所组成。它匹配字符串“dogdogdog”。
【练习答案】
1. 练习:使用反向引用写一个表达式,用于匹配一个人的名字,假设这个人的 first 名字与 last 名字是相同的。
解答:([A-Z][a-zA-Z]*)\\s\\1 注释返回目录
[1] 本文全文译自 Java Tutorial 的 Regular Expressions,标题是译者自拟的。——译者注
[2] Unix 工具,用于文件中的字符串查找,它是最早的正则表达式工具之一。——译者注 [3] 若要退出可以使用 Ctrl + C 来中断。——译者注
[4] 图中的“索引 3”指示是译者所加,原文中并没有。——译者注
[5] 这种方式在 JDK 6.0 以前版本使用需要注意,在字符类中使用这种结构是有 bug 的,不过在 JDK 6.0 中已经修正。——译者注
[6] 若\\E前没有\\Q时会产生 PatternSyntaxException 异常指示语法错误。——译者注
[7] 第一次匹配时仅匹配字符串的开始部分,与\\A类似。(引自 Jeffrey E.F.Friedl, Mastering Regular Expressions, 3rd ed., §3.5.3.3, O'Reilly, 2006.)——译者注
[8] \?,即字符 ? 上半部分的小圆圈( ? )(该字符在 IE 浏览器上无法正确显示,在 Firefox 浏览器上可以正常地显示)。——译者注
[9] JDK 5.0 新增的方法,JDK 1.4 中不能使用。——译者注
[10] JDK 1.4 和 JDK 5.0 适用的版本在所附的源代码中。适用于 JDK 1.4 的文件名
为 RegexTestHarness2V4.java,JDK 1.5 的文件名为 RegexTestHarness2V5.java。——译者注 [11] 第三版是本书的最新版本。第三版的中译本《精通正则表达式》已由电子工业出版社于 2007 年 7 月出版。——译者注 译后记返回目录
带着忐忑不安的心情完成了我的第一篇译篇,但愿这个教程能让大家对 Java 中的正则表达式有更一步的认识。
虽然这是一个关于 Java 正则表达式很好的一个入门教程,但这个教程也有其不足之处,其中仅仅涉及了最为简单的正则表达式,对介绍到的有些问题并未完全展开,比如:字符类中的转义、内嵌标志表达式具体的用法等。对有些常用的表达式,如|(选择结构)也没有涉及。对于非捕获组来说,仅仅提到了内嵌标志表达式,对于诸如(?:X)、(?=X)、(?!X)、(?<=X)、(?X)等等之类的非捕获组结构完全没有涉及。正如译者在序中提到的,这篇文章只为今后学习更高级的正则表达式技术奠定良好的基础。