《Java正则表达式详解(非常适合入门).doc》由会员分享,可在线阅读,更多相关《Java正则表达式详解(非常适合入门).doc(50页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、Java正则表达式教程Regular Expressions of Java Tutorial译者序正则表达式善于处理文本,对匹配、搜索和替换等操作都有意想不到的作用。正因如此,正则表达式现在是作为程序员七种基本技能之一,因此学习和使用它在工作中都能达到很高的效率。正则表达式应用于程序设计语言中,首次是出现在 Perl 语言,这也让 Perl 奠定了正则表达式旗手的地位。现在,它已经深入到了所有的程序设计语言中,在程序设计语言中,正则表达式可以说是标准配置了。Java 中从 JDK 1.4 开始增加了对正则表达式的支持,至此正则表达式成为了 Java 中的基本类库,使用时不需要再导入第三方的类
2、库了。Java 正则表达式的语法来源于象征着正则表达式标准的 Perl 语言,但也不是完全相同的,具体的可以参看 Pattern 类的 API 文档说明。我在一次偶然中发现了位于 站点上的 ,也在那里看到了关于 Java 的正则表达式教程,感觉它不同于其他的正则表达式教程,文中以大量的匹配实例来进行说明。为了能让 Java 学习者能更好地使用正则表达式,就将其完整地译出了。该教程中所介绍的正则表达式应用仅仅是最为简单的(并没有完全地涉及到 Pattern 类支持的所有正则表达式语法,也没有涉及到高级的应用),适合于从未接触过或者是尚未完全明白正则表达式基础的学习者。在学习完该教程后,应该对正则
3、表达式有了初步的了解,并能熟练地运用 java.util.regex 包中的关于正则表达式的类库,为今后学习更高级的正则表达式技术奠定良好的基础。教程中所有的源代码都在 src 目录下,可以直接编译运行。由于当前版本的 是基于 JDK 6.0 的,因此其中的示例程序也用到了 JDK 6.0 中的新增类库,但正则表达式在 JDK 1.4 就已经存在了,为了方便大家使用,改写了部分的源代码,源代码类名中后缀为“V4”的表示用于 JDK 1.4 或以上版本,“V5”的表示用于 JDK 5.0 或以上版本,没有这些后缀的类在各个版本中均可以正常使用。由于译者的水平和技术能力有限,译稿虽经多次校对,难免
4、有疏漏之处,敬请大家批评和指正。若有发现不妥之处,请发送邮件至 ,我会在 中进行勘误,谢谢!火龙果顿首! 2008 年 2 月 27 日 这是由程序员杂志社评出的,刊登在程序员2007 年 3 月刊上。这七种基本技能是:数组,字符串与哈希表、正则表达式、调试、两门语言、一个开发环境、SQL 语言和编写软件的思想。 目录 o o o o o o o o o o o o o o o o o o o o 序本文介绍如何使用 java.util.regex API 作为正则表达式模式匹配。虽然说这个包中可被接受的语法参数与 Perl 是相似的,但我们并不需要掌握 Perl 的语法知识。本教程将从基础开
5、始,逐层深入到更多的高级技巧。下面是各章节的主要内容:0引言粗略地看一下正则表达式,同时也介绍组成 API 的核心类。1测试用具编写了一个简单的应用程序,用于测试正则表达式的模式匹配。2字符串介绍基本的模式匹配、元字符和引用。3字符类描述简单字符类、否定、范围、并集、交集和差集。4预定义字符类描述空白字符、字母和数字字符等基本的预定义字符。5量词使用贪婪(greedy)、勉强(reluctant)和侵占(possessive)量词,来匹配指定表达式 X 的次数。6捕获组解释如何把多个字符作为一个单独的单元进行处理。7边界匹配器描述行、单词和输入的边界。8Pattern 类的方法测试了 Patt
6、ern 中一些有用的方法,以及探究一些高级的特性,诸如:带标记的编译和使用内嵌标记表达式。9Matcher 类的方法描述了 Matcher 类中通常使用的方法。10PatternSyntaxException 类的方法描述了如何检查一个 PatternSyntaxException 异常。11更多的资源要了解更多正则表达式,可以参考这一节。12问题和练习巩固一下本教程所介绍的正则表达式的基本知识,并附有答案。为了区分文档中的正则表达式和普通字符串,均以dabc2的形式表示正则表达式的模式。0引言0.1什么是正则表达式?正则表达式(regular expressions)是一种描述字符串集的方法
7、,它是以字符串集中各字符串的共有特征为依据的。正则表达式可以用于搜索、编辑或者是操作文本和数据。它超出了 Java 程序设计语言的标准语法,因此有必要去学习特定的语法来构建正则表达式。正则表达式的变化是复杂的,一旦你理解了它们是如何被构造的话,你就能解析或者构建任意的正则表达式了。本教程讲授 java.util.regex API 所支持的正则表达式语法,以及介绍几个可运行的例子来说明不同的对象间是如何交互的。在正则表达式的世界中,有不同风格的选择,比如:grep、Perl、Tcl、Python、PHP 和 awk。java.util.regex API 中的正则表达式语法与 Perl 中的最
8、为相似。0.2java.util.regex 包是如何描述正则表达式的?java.util.regex 包主要由三个类所组成:Pattern、Matcher 和 PatternSyntaxException。 Pattern 对象表示一个已编译的正则表达式。Pattern 类没有提供公共的构造方法。要构建一个模式,首先必须调用公共的静态 compile 方法,它将返回一个 Pattern 对象。这个方法接受正则表达式作为第一个参数。本教程的开始部分将教你必需的语法。 Matcher 是一个靠着输入的字符串来解析这个模式和完成匹配操作的对象。与 Pattern 相似,Matcher 也没有定义公
9、共的构造方法,需要通过调用 Pattern 对象的 matcher 方法来获得一个 Matcher 对象。 PatternSyntaxException 对象是一个未检查异常,指示了正则表达式中的一个语法错误。 本教程的最后几节课程会详细地说明各个类。首当其冲的问题是:必须理解正则表达式是如何被构建的,因此下一节引入了一个简单的测试用具,重复地用于探究它们的语法。 1测试用具这节给出了一个可重用的测试用具 ,用于探究构建 API 所支持的正则表达式。使用java RegexTestHarness这个命令来运行,没有被接受的命令行参数。这个应用会不停地循环执行下去,提示用户输入正则表达式和字符串
10、。虽然说使用这个测试用具是可选的,但你会发现它用于探究下文所讨论的测试用例将更为方便。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(No console.); System.exit(1
11、); while (true) Pattern pattern = Ppile(console.readLine(%nEnter your regex: ); Matcher matcher = pattern.matcher(console.readLine(Enter input string to search: ); boolean found = false; while (matcher.find() console.format(I found the text %s starting at index %d + and ending at index %d.%n, matche
12、r.group(), matcher.start(), matcher.end(); found = true; if (!found) console.format(No match found.%n); 在继续下一节之前,确认开发环境支持必需的包,并保存和编译这段代码。 【译者注】由于当前版本的 是基于 JDK 6.0 编写的,上述的测试用具由于使用到 JDK 6.0 中新增的类库(java.io.Console),所以该用具只能在 JDK 6.0 的环境中编译运行,由于 Console 访问操作系统平台上的控制台,因此这个测试用具只能在操作系统的字符控制台中运行,不能运行在 IDE 的控
13、制台中。正则表达式是 JDK 1.4 所增加的类库,为了兼容 JDK 1.4 和 JDK 5.0 的版本,重新改写了这个测试用具,让其能适用于不同的版本。JDK 5.0 适用的测试用具(,该用具可以在 IDE 中执行),建议 JDK 6.0 环境也采用该用具。import java.util.Scanner; import java.util.regex.Matcher; import java.util.regex.Pattern; public class RegexTestHarnessV5 public static void main(String args) Scanner sca
14、nner = new Scanner(System.in); while (true) System.out.printf(%nEnter your regex: ); Pattern pattern = Ppile(scanner.nextLine(); System.out.printf(Enter input string to search: ); Matcher matcher = pattern.matcher(scanner.nextLine(); boolean found = false; while (matcher.find() System.out.printf( I
15、found the text %s starting at index %d and ending at index %d.%n, matcher.group(), matcher.start(), matcher.end() ); found = true; if (!found) System.out.printf(No match found.%n); JDK 1.4 适用的测试用具():import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.IOException; import
16、 java.io.InputStreamReader; import java.util.regex.Matcher; import java.util.regex.Pattern; public class RegexTestHarnessV4 public static void main(String args) throws IOException BufferedReader br = new BufferedReader( new InputStreamReader(new BufferedInputStream(System.in) ); while (true) System.
17、out.print(nEnter your regex: ); Pattern pattern = Ppile(br.readLine(); System.out.print(Enter input string to search: ); Matcher matcher = pattern.matcher(br.readLine(); boolean found = false; while (matcher.find() System.out.println(I found the text + matcher.group() + starting at index + matcher.s
18、tart() + and ending at index + matcher.end() + .); found = true; if (!found) System.out.println(No match found.); 2字符串在大多数的情况下,API所支持模式匹配的基本形式是匹配字符串,如果正则表达式是foo,输入的字符串也是 foo,这个匹配将会是成功的,因为这两个字符串是相同的。试着用测试用具来测试一下: Enter your regex: fooEnter input string to search: fooI found the text foo starting at i
19、ndex 0 and ending at index 3.结果确实是成功的。注意当输入的字符串是 3 个字符长度的时候,开始的索引是 0,结束的索引是 3。这个是约定俗成的,范围包括开始的索引,不包括结束的索引,如下图所示:图 1字符串“foo”的单元格编号和索引值字符串中的每一个字符位于其自身的单元格(cell)中,在每个单元格之间有索引指示位。字符串“foo”始于索引 0 处,止于索引 3 处,即使是这些字符它们自己仅占据了 0、1 和 2 号单元格。就子序列匹配而言,你会注意到一些重叠,下一次匹配开始索引与前一次匹配的结束索引是相同的:Enter your regex: fooEnter
20、 input string to search: foofoofooI found the text foo starting at index 0 and ending at index 3.I found the text foo starting at index 3 and ending at index 6.I found the text foo starting at index 6 and ending at index 9.2.1元字符API 也支持许多可以影响模式匹配的特殊字符。把正则表达式改为cat.并输入字符串“cats”,输出如下所示: Enter your rege
21、x: cat.Enter input string to search: catsI found the text cats starting at index 0 and ending at index 4.虽然在输入的字符串中没有点(.),但这个匹配仍然是成功的。这是由于点(.)是一个元字符(metacharacters)(被这个匹配翻译成了具有特殊意义的字符了)。这个例子为什么能匹配成功的原因在于,元字符.指的是“任意字符”。API 所支持的元字符有:(-$|)?*+. 注意:在学习过更多的如何构建正则表达式后,你会碰到这些情况:上面的这些特殊字符不应该被处理为元字符。然而也能够使用这个
22、清单来检查一个特殊的字符是否会被认为是元字符。例如,字符 !、 和 # 决不会有特殊的意义。 有两种方法可以强制将元字符处理成为普通字符:1. 在元字符前加上反斜线();2. 把它放在Q(引用开始)和E(引用结束)之间。在使用这种技术时,Q和E能被放于表达式中的任何位置(假设先出现Q)3字符类如果你曾看过 类的说明,会看到一些构建正则表达式的概述。在这一节中你会发现下面的一些表达式:字符类abca, b 或 c(简单类)abc除 a, b 或 c 之外的任意字符(取反)a-zA-Za 到 z,或 A 到 Z,包括(范围)a-dm-pa 到 d,或 m 到 p:a-dm-p(并集)a-z&def
23、d,e 或 f(交集)a-z&bc除 b 和 c 之外的 a 到 z 字符:ad-z(差集)a-z&m-pa 到 z,并且不包括 m 到 p:a-lq-z(差集)左边列指定正则表达式构造,右边列描述每个构造的匹配的条件。注意:“字符类(character class)”这个词中的“类(class)”指的并不是一个 .class 文件。在正则表达式的语义中,字符类是放在方括号里的字符集,指定了一些字符中的一个能被给定的字符串所匹配。 3.1简单类(Simple Classes)字符类最基本的格式是把一些字符放在一对方括号内。例如:正则表达式bcrat会匹配“bat”、“cat”或者“rat”,这
24、是由于其定义了一个字符类(接受“b”、“c”或“r”中的一个字符)作为它的首字符。 Enter your regex: bcratEnter input string to search: batI found the text bat starting at index 0 and ending at index 3.Enter your regex: bcratEnter input string to search: catI found the text cat starting at index 0 and ending at index 3.Enter your regex: bc
25、ratEnter input string to search: ratI found the text rat starting at index 0 and ending at index 3.Enter your regex: bcratEnter input string to search: hatNo match found.在上面的例子中,在第一个字符匹配字符类中所定义字符中的一个时,整个匹配就是成功的。 3.1.1否定要匹配除那些列表之外所有的字符时,可以在字符类的开始处加上元字符,这种就被称为否定(negation)。 Enter your regex: bcratEnter
26、 input string to search: batNo match found.Enter your regex: bcratEnter input string to search: catNo match found.Enter your regex: bcratEnter input string to search: ratNo match found.Enter your regex: bcratEnter input string to search: hatI found the text hat starting at index 0 and ending at inde
27、x 3.在输入的字符串中的第一个字符不包含在字符类中所定义字符中的一个时,匹配是成功的。 3.1.2范围有时会想要定义一个包含值范围的字符类,诸如,“a 到 h”的字母或者是“1 到 5”的数字。指定一个范围,只要在被匹配的首字符和末字符间插入-元字符,比如:1-5或者是a-h。也可以在类里每个的边上放置不同的范围来提高匹配的可能性,例如:a-zA-Z将会匹配 a 到 z(小写字母)或者 A 到 Z(大写字母)中的任何一个字符。下面是一些范围和否定的例子:Enter your regex: a-cEnter input string to search: aI found the text a
28、 starting at index 0 and ending at index 1.Enter your regex: a-cEnter input string to search: bI found the text b starting at index 0 and ending at index 1.Enter your regex: a-cEnter input string to search: cI found the text c starting at index 0 and ending at index 1.Enter your regex: a-cEnter inpu
29、t string to search: dNo match found.Enter your regex: foo1-5Enter input string to search: foo1I found the text foo1 starting at index 0 and ending at index 4.Enter your regex: foo1-5Enter input string to search: foo5I found the text foo5 starting at index 0 and ending at index 4.Enter your regex: fo
30、o1-5Enter input string to search: foo6No match found.Enter your regex: foo1-5Enter input string to search: foo1No match found.Enter your regex: foo1-5Enter input string to search: foo6I found the text foo6 starting at index 0 and ending at index 4.3.1.3并集可以使用并集(union)来建一个由两个或两个以上字符类所组成的单字符类。构建一个并集,只
31、要在一个字符类的边上嵌套另外一个,比如:0-46-8,这种奇特方式构建的并集字符类,可以匹配 0,1,2,3,4,6,7,8 这几个数字。 Enter your regex: 0-46-8Enter input string to search: 0I found the text 0 starting at index 0 and ending at index 1.Enter your regex: 0-46-8Enter input string to search: 5No match found.Enter your regex: 0-46-8Enter input string t
32、o search: 6I found the text 6 starting at index 0 and ending at index 1.Enter your regex: 0-46-8Enter input string to search: 8I found the text 8 starting at index 0 and ending at index 1.Enter your regex: 0-46-8Enter input string to search: 9No match found.3.1.4交集建一个仅仅匹配自身嵌套类中公共部分字符的字符类时,可以像0-9&345
33、中那样使用&。这种方式构建出来的交集(intersection)简单字符类,仅仅以匹配两个字符类中的 3,4,5 共有部分。 Enter your regex: 0-9&345Enter input string to search: 3I found the text 3 starting at index 0 and ending at index 1.Enter your regex: 0-9&345Enter input string to search: 4I found the text 4 starting at index 0 and ending at index 1.Ent
34、er your regex: 0-9&345Enter input string to search: 5I found the text 5 starting at index 0 and ending at index 1.Enter your regex: 0-9&345Enter input string to search: 2No match found.Enter your regex: 0-9&345Enter input string to search: 6No match found.下面演示两个范围交集的例子: Enter your regex: 2-8&4-6Ente
35、r input string to search: 3No match found.Enter your regex: 2-8&4-6Enter input string to search: 4I found the text 4 starting at index 0 and ending at index 1.Enter your regex: 2-8&4-6Enter input string to search: 5I found the text 5 starting at index 0 and ending at index 1.Enter your regex: 2-8&4-
36、6Enter input string to search: 6I found the text 6 starting at index 0 and ending at index 1.Enter your regex: 2-8&4-6Enter input string to search: 7No match found.3.1.5差集最后,可以使用差集(subtraction)来否定一个或多个嵌套的字符类,比如:0-9&345,这个是构建一个匹配除 3,4,5 之外所有 0 到 9 间数字的简单字符类。 Enter your regex: 0-9&345Enter input strin
37、g to search: 2I found the text 2 starting at index 0 and ending at index 1.Enter your regex: 0-9&345Enter input string to search: 3No match found.Enter your regex: 0-9&345Enter input string to search: 4No match found.Enter your regex: 0-9&345Enter input string to search: 5No match found.Enter your r
38、egex: 0-9&345Enter input string to search: 6I found the text 6 starting at index 0 and ending at index 1.Enter your regex: 0-9&345Enter input string to search: 9I found the text 9 starting at index 0 and ending at index 1.到此为止,已经涵盖了如何建立字符类的部分。在继续下一节之前,可以试着回想一下那张。 4预定义字符类Pattern 的 API 包有许多有用的预定义字符类(p
39、redefined character classes),提供了常用正则表达式的简写形式。预定义字符类.任何字符(匹配或者不匹配行结束符)d数字字符:0-9D非数字字符:0-9s空白字符:tnx0BfrS非空白字符:sw单词字符:a-zA-Z_0-9W非单词字符:w上表中,左列是构造右列字符类的简写形式。例如:d指的是数字范围(09),w指的是单词字符(任何大小写字母、下划线或者是数字)。无论何时都有可能使用预定义字符类,它可以使代码更易阅读,更易从难看的字符类中排除错误。以反斜线()开始的构造称为转义构造(escaped constructs)。回顾一下在 一节中的转义构造,在那里我们提及了
40、使用反斜线,以及用于引用的Q和E。在字符串中使用转义构造,必须在一个反斜线前再增加一个反斜用于字符串的编译,例如:001private final String REGEX = d;/ 单个数字这个例子中d是正则表达式,另外的那个反斜线是用于代码编译所必需的。但是测试用具读取的表达式,是直接从控制台中输入的,因此不需要那个多出来的反斜线。下面的例子说明了预字义字符类的用法:Enter your regex: .Enter input string to search: I found the text starting at index 0 and ending at index 1.Ente
41、r your regex: .Enter input string to search: 1I found the text 1 starting at index 0 and ending at index 1.Enter your regex: .Enter input string to search: aI found the text a starting at index 0 and ending at index 1.Enter your regex: dEnter input string to search: 1I found the text 1 starting at index 0 and ending at index 1.Enter your regex: dEnter input string to search: aNo match found.Enter your regex: DEnter input string to search: 1No match found.Enter your regex: DEnter input string to search: aI found the text a starting at in
限制150内