Java
正则表达式教程 [1]
Regular Expressions of Java Tutorial
译者序
正则表达式善于处理文本,对匹配、搜索和替换等操作都有意想不到的作用。正因如此,正则表达式现在是作为程序员七种基本技能之一,因此学习和使用它在工作中都能达到很高的效率。
正则表达式应用于程序设计语言中,首次是出现在 Perl 语言,这也让 Perl 奠定了正则表达式旗手的地位。现在,它已经深入到了所有的程序设计语言中,在程序设计语言中,正则表达式可以说是标准配置了。
Java 中从 JDK 1.4 开始增加了对正则表达式的支持,至此正则表达式成为了 Java 中的基本类库,使用时不需要再导入第三方的类库了。Java 正则表达式的语法来源于象征着正则表达式标准的 Perl 语言,但也不是完全相同的,具体的可以参看 Pattern 类的 API 文档说明。
我在一次偶然中发现了位于 java.sun.com 站点上的 Java Tutorial,也在那里看到了关于 Java 的正则表达式教程,感觉它不同于其他的正则表达式教程,文中以大量的匹配实例来进行说明。为了能让 Java 学习者能更好地使用正则表达式,就将其完整地译出了。该教程中所介绍的正则表达式应用仅仅是最为简单的(并没有完全地涉及到 Pattern 类支持的所有正则表达式语法,也没有涉及到高级的应用),适合于从未接触过或者是尚未完全明白正则表达式基础的学习者。在学习完该教程后,应该对正则表达式有了初步的了解,并能熟练地运用 java.util.regex 包中的关于正则表达式的类库,为今后学习更高级的正则表达式技术奠定良好的基础。
教程中所有的源代码都在 src 目录下,可以直接编译运行。由于当前版本的 Java Tutorial 是基于 JDK 6.0 的,因此其中的示例程序也用到了 JDK 6.0 中的新增类库,但正则表达式在 JDK 1.4 就已经存在了,为了方便大家使用,改写了部分的源代码,源代码类名中后缀为“V4”的表示用于 JDK 1.4 或以上版本,“V5”的表示用于 JDK 5.0 或以上版本,没有这些后缀的类在各个版本中均可以正常使用。
由于译者的水平和技术能力有限,译稿虽经多次校对,难免有疏漏之处,敬请大家批评和指正。若有发现不妥之处,请发送邮件至 FrankieGao123@gmail.com,我会在 blog 中进行勘误,谢谢! 火龙果顿首!
2008 年 2 月 27 日
* 这是由《程序员》杂志社评出的,刊登在《程序员》2007 年 3 月刊上。这七种基本技能是:数组,字符串与哈希表、正则表达式、调试、两门语言、一个开发环境、SQL 语言和编写软件的思想。 目录
*
? ? ? o o
译者序 序 0 引言
0.1 什么是正则表达式?
0.2 java.util.regex 包是如何描述正则表达式的?
? ? o ? o ? ? ? ? ? ? ? o o o ? o o ? ? o o o o o o ? o o o o
法
1 测试用具 2 字符串
2.1 元字符
3 字符类
3.1 简单类
3.1.1 否定 3.1.2 范围 3.1.3 并集 3.1.4 交集 3.1.5 差集
4 预定义字符类 5 量词
5.1 零长度匹配
5.2 捕获组和字符类中的量词 5.3 贪婪、勉强和侵占量词间的不同
6 捕获组
6.1 编号方式 6.2 反向引用
7 边界匹配器 8 Pattern 类的方法
8.1 使用标志构建模式 8.2 内嵌标志表达式
8.3 使用 matches(String, CharSequence) 方法 8.4 使用 split(String) 方法 8.5 其他有用的方法
8.6 在 java.lang.String 中等价的 Pattern 方法
9 Matcher 类的方法
9.1 使用 start 和 end 方法
9.2 使用 matches 和 lookingAt 方法
9.3 使用 replaceFirst(String) 和 replaceAll(String) 方法
9.4 使用 appendReplacement(StringBuffer, String) 和 appendTail(StringBuffer) 方
o ? ? ? ? ?
9.5 在 java.lang.String 中等价的 Matcher 方法
10 PatternSyntaxException 类的方法 11 更多的资源 12 问题和练习 注释 译后记
序返回目录
本文介绍如何使用 java.util.regex API 作为正则表达式模式匹配。虽然说这个包中可被接受的语法参数与 Perl 是相似的,但我们并不需要掌握 Perl 的语法知识。本教程将从基础开始,逐层深入到更多的高级技巧。下面是各章节的主要内容: 0 引言
粗略地看一下正则表达式,同时也介绍组成 API 的核心类。 1 测试用具
编写了一个简单的应用程序,用于测试正则表达式的模式匹配。 2 字符串
介绍基本的模式匹配、元字符和引用。 3 字符类
描述简单字符类、否定、范围、并集、交集和差集。 4 预定义字符类
描述空白字符、字母和数字字符等基本的预定义字符。 5 量词
使用贪婪(greedy)、勉强(reluctant)和侵占(possessive)量词,来匹配指定表达式 X 的次数。 6 捕获组
解释如何把多个字符作为一个单独的单元进行处理。 7 边界匹配器
描述行、单词和输入的边界。 8 Pattern 类的方法
测试了 Pattern 中一些有用的方法,以及探究一些高级的特性,诸如:带标记的编译和使用内嵌标记表达式。
9 Matcher 类的方法
描述了 Matcher 类中通常使用的方法。 10 PatternSyntaxException 类的方法
描述了如何检查一个 PatternSyntaxException 异常。 11 更多的资源
要了解更多正则表达式,可以参考这一节。 12 问题和练习
巩固一下本教程所介绍的正则表达式的基本知识,并附有答案。
为了区分文档中的正则表达式和普通字符串,均以\\d[abc]{2}的形式表示正则表达式的模式。 0 引言返回目录
0.1 什么是正则表达式?返回目录
正则表达式(regular expressions)是一种描述字符串集的方法,它是以字符串集中各字符串的共有特征为依据的。正则表达式可以用于搜索、编辑或者是操作文本和数据。它超出了 Java 程序设计语言的标准语法,因此有必要去学习特定的语法来构建正则表达式。正则表达式的变化是复杂的,一旦你理解了它们是如何被构造的话,你就能解析或者构建任意的正则表达式了。
本教程讲授 java.util.regex API 所支持的正则表达式语法,以及介绍几个可运行的例子来说明不同的对象间是如何交互的。在正则表达式的世界中,有不同风格的选择,比如:grep[2]、Perl、Tcl、Python、PHP 和 awk。java.util.regex API 中的正则表达式语法与 Perl 中的最为相似。 0.2 java.util.regex 包是如何描述正则表达式的?返回目录
java.util.regex 包主要由三个类所组成:Pattern、Matcher 和 PatternSyntaxException。
? Pattern 对象表示一个已编译的正则表达式。Pattern 类没有提供公共的构造方法。要构建一个模
式,首先必须调用公共的静态 compile 方法,它将返回一个 Pattern 对象。这个方法接受正则表达式作为第一个参数。本教程的开始部分将教你必需的语法。
? Matcher 是一个靠着输入的字符串来解析这个模式和完成匹配操作的对象。与 Pattern 相似,
Matcher 也没有定义公共的构造方法,需要通过调用 Pattern 对象的 matcher 方法来获得一个 Matcher 对象。
? PatternSyntaxException 对象是一个未检查异常,指示了正则表达式中的一个语法错误。
本教程的最后几节课程会详细地说明各个类。首当其冲的问题是:必须理解正则表达式是如何被构建的,因此下一节引入了一个简单的测试用具,重复地用于探究它们的语法。 1 测试用具返回目录
这节给出了一个可重用的测试用具 RegexTestHarness.java,用于探究构建 API 所支持的正则表达式。使用
java RegexTestHarness
这个命令来运行,没有被接受的命令行参数。这个应用会不停地循环执行下去[3],提示用户输入正则表达式和字符串。虽然说使用这个测试用具是可选的,但你会发现它用于探究下文所讨论的测试用例将更为方便。
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
import java.io.Console;
import java.util.regex.Pattern; import java.util.regex.Matcher;
public class RegexTestHarness {
public static void main(String[] args) { Console console = System.console(); if (console == null) {
System.err.println(\ System.exit(1); }
while (true) {
Pattern pattern =
Pattern.compile(console.readLine(\
Matcher matcher = pattern.matcher(console.readLine(\input string to search: \
boolean found = false; while (matcher.find()) {
console.format(\index %d \
\ matcher.group(), matcher.start(), matcher.end());
found = true; }
if (!found) {
console.format(\ } } } }