java正则表达式语法详解及其使用代码实例

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

               

代码下载地址:http://www.zuidaima.com/share/1835085544524800.htm

原文:java正则表达式语法详解及其使用代码实例

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 语言和编写软件的思想。

目录

  

返回目录

  本文介绍如何使用 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],提示用户输入正则表达式和字符串。虽然说使用这个测试用具是可选的,但你会发现它用于探究下文所讨论的测试用例将更为方便。

package com.zuidaima.util;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);         }                while (true) {             Pattern pattern = Pattern.compile(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",                         matcher.group(), matcher.start(), matcher.end());                 found = true;             }             if (!found) {                 console.format("No match found.%n");             }         }     } }

  在继续下一节之前,确认开发环境支持必需的包,并保存和编译这段代码。

【译者注】

  由于当前版本的 Java Tutorial 是基于 JDK 6.0 编写的,上述的测试用具由于使用到 JDK 6.0 中新增的类库(java.io.Console),所以该用具只能在 JDK 6.0 的环境中编译运行,由于 Console 访问操作系统平台上的控制台,因此这个测试用具只能在操作系统的字符控制台中运行,不能运行在 IDE 的控制台中。
  正则表达式是 JDK 1.4 所增加的类库,为了兼容 JDK 1.4 和 JDK 5.0 的版本,重新改写了这个测试用具,让其能适用于不同的版本。
  JDK 5.0 适用的测试用具(RegexTestHarnessV5.java,该用具可以在 IDE 中执行),建议 JDK 6.0 环境也采用该用具。

package com.zuidaima.util;import java.util.Scanner; import java.util.regex.Matcher; import java.util.regex.Pattern;  public class RegexTestHarnessV5 {      public static void main(String[] args) {         Scanner scanner = new Scanner(System.in);         while (true) {             System.out.printf("%nEnter your regex: ");             Pattern pattern = Pattern.compile(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 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 适用的测试用具(RegexTestHarnessV4.java):

package com.zuidaima.util;import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.IOException; import 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.out.print("\nEnter your regex: ");             Pattern pattern = Pattern.compile(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.start() +                         " 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 index 0 and ending at index 3.

  结果确实是成功的。注意当输入的字符串是 3 个字符长度的时候,开始的索引是 0,结束的索引是 3。这个是约定俗成的,范围包括开始的索引,不包括结束的索引,如下图所示:


图 1 字符串“foo”的单元格编号和索引值[4]

  字符串中的每一个字符位于其自身的单元格(cell)中,在每个单元格之间有索引指示位。字符串“foo”始于索引 0 处,止于索引 3 处,即使是这些字符它们自己仅占据了 0、1 和 2 号单元格。
  就子序列匹配而言,你会注意到一些重叠,下一次匹配开始索引与前一次匹配的结束索引是相同的:

Enter your regex: fooEnter 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 regex: cat.Enter input string to search: catsI found the text "cats" starting at index 0 and ending at index 4.

  虽然在输入的字符串中没有点(.),但这个匹配仍然是成功的。这是由于点(.)是一个元字符(metacharacters)(被这个匹配翻译成了具有特殊意义的字符了)。这个例子为什么能匹配成功的原因在于,元字符.指的是“任意字符”。
  API 所支持的元字符有:([{\^-$|}])?*+.

注意:在学习过更多的如何构建正则表达式后,你会碰到这些情况:上面的这些特殊字符不应该被处理为元字符。然而也能够使用这个清单来检查一个特殊的字符是否会被认为是元字符。例如,字符 !、@ 和 # 决不会有特殊的意义。

  有两种方法可以强制将元字符处理成为普通字符:
  1. 在元字符前加上反斜线(\);
  2. 把它放在\Q(引用开始)和\E(引用结束)之间[5]。在使用这种技术时,\Q\E能被放于表达式中的任何位置(假设先出现\Q[6]

3 字符类返回目录

  如果你曾看过 Pattern 类的说明,会看到一些构建正则表达式的概述。在这一节中你会发现下面的一些表达式:

字符类
[abc]a, b 或 c(简单类)
[^abc]除 a, b 或 c 之外的任意字符(取反)
[a-zA-Z]a 到 z,或 A 到 Z,包括(范围)
[a-d[m-p]]a 到 d,或 m 到 p:[a-dm-p](并集)
[a-z&&[def]]d,e 或 f(交集)
[a-z&&[^bc]]除 b 和 c 之外的 a 到 z 字符:[ad-z](差集)
[a-z&&[^m-p]]a 到 z,并且不包括 m 到 p:[a-lq-z](差集)

  左边列指定正则表达式构造,右边列描述每个构造的匹配的条件。

注意:“字符类(character class)”这个词中的“类(class)”指的并不是一个 .class 文件。在正则表达式的语义中,字符类是放在方括号里的字符集,指定了一些字符中的一个能被给定的字符串所匹配。

3.1 简单类(Simple Classes)返回目录

  字符类最基本的格式是把一些字符放在一对方括号内。例如:正则表达式[bcr]at会匹配“bat”、“cat”或者“rat”,这是由于其定义了一个字符类(接受“b”、“c”或“r”中的一个字符)作为它的首字符。

Enter your regex: [bcr]atEnter input string to search: batI found the text "bat" starting at index 0 and ending at index 3.Enter your regex: [bcr]atEnter input string to search: catI found the text "cat" starting at index 0 and ending at index 3.Enter your regex: [bcr]atEnter input string to search: ratI found the text "rat" starting at index 0 and ending at index 3.Enter your regex: [bcr]atEnter input string to search: hatNo match found.

  在上面的例子中,在第一个字符匹配字符类中所定义字符中的一个时,整个匹配就是成功的。

3.1.1 否定返回目录

  要匹配除那些列表之外所有的字符时,可以在字符类的开始处加上^元字符,这种就被称为否定(negation)。

Enter your regex: [^bcr]atEnter input string to search: batNo match found.Enter your regex: [^bcr]atEnter input string to search: catNo match found.Enter your regex: [^bcr]atEnter input string to search: ratNo match found.Enter your regex: [^bcr]atEnter input string to search: hatI found the text "hat" starting at index 0 and ending at index 3.

  在输入的字符串中的第一个字符不包含在字符类中所定义字符中的一个时,匹配是成功的。

3.1.2 范围返回目录

  有时会想要定义一个包含值范围的字符类,诸如,“a 到 h”的字母或者是“1 到 5”的数字。指定一个范围,只要在被匹配的首字符和末字符间插入-元字符,比如:[1-5]或者是[a-h]。也可以在类里每个的边上放置不同的范围来提高匹配的可能性,例如:[a-zA-Z]将会匹配 a 到 z(小写字母)或者 A 到 Z(大写字母)中的任何一个字符。
  下面是一些范围和否定的例子:

Enter your regex: [a-c]Enter input string to search: aI found the text "a" starting at index 0 and ending at index 1.Enter your regex: [a-c]Enter input string to search: bI found the text "b" starting at index 0 and ending at index 1.Enter your regex: [a-c]Enter input string to search: cI found the text "c" starting at index 0 and ending at index 1.Enter your regex: [a-c]Enter input string to search: dNo match found.Enter your regex: foo[1-5]Enter input string to search: foo1I found the text "foo1" starting at index 0 and ending at index 4.Enter your regex: foo[1-5]Enter input string to search: foo5I found the text "foo5" starting at index 0 and ending at index 4.Enter your regex: foo[1-5]Enter input string to search: foo6No match found.Enter your regex: foo[^1-5]Enter input string to search: foo1No match found.Enter your regex: foo[^1-5]Enter input string to search: foo6I found the text "foo6" starting at index 0 and ending at index 4.

3.1.3 并集返回目录

  可以使用并集(union)来建一个由两个或两个以上字符类所组成的单字符类。构建一个并集,只要在一个字符类的边上嵌套另外一个,比如:[0-4[6-8]],这种奇特方式构建的并集字符类,可以匹配 0,1,2,3,4,6,7,8 这几个数字。

Enter your regex: [0-4[6-8]]Enter input string to search: 0I found the text "0" starting at index 0 and ending at index 1.Enter your regex: [0-4[6-8]]Enter input string to search: 5No match found.Enter your regex: [0-4[6-8]]Enter input string to search: 6I found the text "6" starting at index 0 and ending at index 1.Enter your regex: [0-4[6-8]]Enter input string to search: 8I found the text "8" starting at index 0 and ending at index 1.Enter your regex: [0-4[6-8]]Enter input string to search: 9No match found.

3.1.4 交集返回目录

  建一个仅仅匹配自身嵌套类中公共部分字符的字符类时,可以像[0-9&&[345]]中那样使用&&。这种方式构建出来的交集(intersection)简单字符类,仅仅以匹配两个字符类中的 3,4,5 共有部分。

Enter your regex: [0-9&&[345]]Enter input string to search: 3I found the text "3" starting at index 0 and ending at index 1.Enter your regex: [0-9&&[345]]Enter input string to search: 4I found the text "4" starting at index 0 and ending at index 1.Enter your regex: [0-9&&[345]]Enter input string to search: 5I found the text "5" starting at index 0 and ending at index 1.Enter your regex: [0-9&&[345]]Enter input string to search: 2No match found.Enter your regex: [0-9&&[345]]Enter input string to search: 6No match found.

  下面演示两个范围交集的例子:

Enter your regex: [2-8&&[4-6]]Enter input string to search: 3No match found.Enter your regex: [2-8&&[4-6]]Enter input string to search: 4I found the text "4" starting at index 0 and ending at index 1.Enter your regex: [2-8&&[4-6]]Enter input string to search: 5I found the text "5" starting at index 0 and ending at index 1.Enter your regex: [2-8&&[4-6]]Enter input string to search: 6I found the text "6" starting at index 0 and ending at index 1.Enter your regex: [2-8&&[4-6]]Enter input string to search: 7No match found.

3.1.5 差集返回目录

  最后,可以使用差集(subtraction)来否定一个或多个嵌套的字符类,比如:[0-9&&[^345]],这个是构建一个匹配除 3,4,5 之外所有 0 到 9 间数字的简单字符类。

Enter your regex: [0-9&&[^345]]Enter input string to search: 2I found the text "2" starting at index 0 and ending at index 1.Enter your regex: [0-9&&[^345]]Enter input string to search: 3No match found.Enter your regex: [0-9&&[^345]]Enter input string to search: 4No match found.Enter your regex: [0-9&&[^345]]Enter input string to search: 5No match found.Enter your regex: [0-9&&[^345]]Enter input string to search: 6I found the text "6" starting at index 0 and ending at index 1.Enter your regex: [0-9&&[^345]]Enter input string to search: 9I found the text "9" starting at index 0 and ending at index 1.

  到此为止,已经涵盖了如何建立字符类的部分。在继续下一节之前,可以试着回想一下那张字符类表

4 预定义字符类返回目录

  Pattern 的 API 包有许多有用的预定义字符类(predefined character classes),提供了常用正则表达式的简写形式。

预定义字符类
.任何字符(匹配或者不匹配行结束符)
\d数字字符:[0-9]
\D非数字字符:[^0-9]
\s空白字符:[\t\n\x0B\f\r]
\S非空白字符:[^\s]
\w单词字符:[a-zA-Z_0-9]
\W非单词字符:[^\w]

  上表中,左列是构造右列字符类的简写形式。例如:\d指的是数字范围(0~9),\w指的是单词字符(任何大小写字母、下划线或者是数字)。无论何时都有可能使用预定义字符类,它可以使代码更易阅读,更易从难看的字符类中排除错误。
  以反斜线(\)开始的构造称为转义构造(escaped constructs)。回顾一下在 字符串 一节中的转义构造,在那里我们提及了使用反斜线,以及用于引用的\Q\E。在字符串中使用转义构造,必须在一个反斜线前再增加一个反斜用于字符串的编译,例如:

 

001

private 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.Enter 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 index 0 and ending at index 1.Enter your regex: \sEnter input string to search:  I found the text " " starting at index 0 and ending at index 1.Enter your regex: \sEnter input string to search: aNo match found.Enter your regex: \SEnter input string to search:  No match found.Enter your regex: \SEnter input string to search: aI found the text "a" starting at index 0 and ending at index 1.Enter your regex: \wEnter input string to search: aI found the text "a" starting at index 0 and ending at index 1.Enter your regex: \wEnter input string to search: !No match found.Enter your regex: \WEnter input string to search: aNo match found.Enter your regex: \WEnter input string to search: !I found the text "!" starting at index 0 and ending at index 1.

  在开始的三个例子中,正则表达式是简单的,.(“点”元字符)表示“任意字符”,因此,在所有的三个例子(随意地选取了“@”字符,数字和字母)中都是匹配成功的。在接下来的例子中,都使用了预定义字符类表格中的单个正则表达式构造。你应该可以根据这张表指出前面每个匹配的逻辑:
  \d 匹配数字字符
  \s 匹配空白字符
  \w 匹配单词字符
  也可以使用意思正好相反的大写字母:
  \D 匹配非数字字符
  \S 匹配非空白字符
  \W 匹配非单词字符

5 量词返回目录

  这一节我们来看一下贪婪(greedy)、勉强(reluctant)和侵占(possessive)量词,来匹配指定表达式X的次数。
  量词(quantifiers)允许指定匹配出现的次数,方便起见,当前 Pattern API 规范下,描述了贪婪、勉强和侵占三种量词。首先粗略地看一下,量词X?X??X?+都允许匹配 X 零次或一次,精确地做同样的事情,但它们之间有着细微的不同之处,在这节结束前会进行说明。

量 词 种 类意  义
贪婪勉强侵占
X?X??X?+匹配 X 零次或一次
X*X*?X*+匹配 X 零次或多次
X+X+?X++匹配 X 一次或多次
X{n}X{n}?X{n}+匹配 X n 次
X{n,}X{n,}?X{n,}+匹配 X 至少 n 次
X{n,m}X{n,m}?X{n,m}+匹配 X 至少 n 次,但不多于 m 次

  那我们现在就从贪婪量词开始,构建三个不同的正则表达式:字母a后面跟着?*+。接下来看一下,用这些表达式来测试输入的字符串是空字符串时会发生些什么:

Enter your regex: a?Enter input string to search: I found the text "" starting at index 0 and ending at index 0.Enter your regex: a*Enter input string to search: I found the text "" starting at index 0 and ending at index 0.Enter your regex: a+Enter input string to search: No match found.

5.1 零长度匹配返回目录

  在上面的例子中,开始的两个匹配是成功的,这是因为表达式a?a*都允许字符出现零次。就目前而言,这个例子不像其他的,也许你注意到了开始和结束的索引都是 0。输入的空字符串没有长度,因此该测试简单地在索引 0 上匹配什么都没有,诸如此类的匹配称之为零长度匹配(zero-length matches)。零长度匹配会出现在以下几种情况:输入空的字符串、在输入字符串的开始处、在输入字符串最后字符的后面,或者是输入字符串中任意两个字符之间。由于它们开始和结束的位置有着相同的索引,因此零长度匹配是容易被发现的。
  我们来看一下关于零长度匹配更多的例子。把输入的字符串改为单个字符“a”,你会注意到一些有意思的事情:

Enter your regex: a?Enter input string to search: aI found the text "a" starting at index 0 and ending at index 1.I found the text "" starting at index 1 and ending at index 1.Enter your regex: a*Enter input string to search: aI found the text "a" starting at index 0 and ending at index 1.I found the text "" starting at index 1 and ending at index 1.Enter your regex: a+Enter input string to search: aI found the text "a" starting at index 0 and ending at index 1.

  所有的三个量词都是用来寻找字母“a”的,但是前面两个在索引 1 处找到了零长度匹配,也就是说,在输入字符串最后一个字符的后面。回想一下,匹配把字符“a”看作是位于索引 0 和索引 1 之间的单元格中,并且测试用具一直循环下去直到不再有匹配为止。依赖于所使用的量词不同,最后字符后面的索引“什么也没有”的存在可以或者不可以触发一个匹配。
  现在把输入的字符串改为一行 5 个“a”时,会得到下面的结果:

Enter your regex: a?Enter input string to search: aaaaaI found the text "a" starting at index 0 and ending at index 1.I found the text "a" starting at index 1 and ending at index 2.I found the text "a" starting at index 2 and ending at index 3.I found the text "a" starting at index 3 and ending at index 4.I found the text "a" starting at index 4 and ending at index 5.I found the text "" starting at index 5 and ending at index 5.Enter your regex: a*Enter input string to search: aaaaaI found the text "aaaaa" starting at index 0 and ending at index 5.I found the text "" starting at index 5 and ending at index 5.Enter your regex: a+Enter input string to search: aaaaaI found the text "aaaaa" starting at index 0 and ending at index 5.

  在“a”出现零次或一次时,表达式a?寻找到所匹配的每一个字符。表达式a*找到了两个单独的匹配:第一次匹配到所有的字母“a”,然后是匹配到最后一个字符后面的索引 5。最后,a+匹配了所有出现的字母“a”,忽略了在最后索引处“什么都没有”的存在。
  在这里,你也许会感到疑惑,开始的两个量词在遇到除了“a”的字母时会有什么结果。例如,在“ababaaaab”中遇到了字母“b”会发生什么呢?
  下面我们来看一下:

Enter your regex: a?Enter input string to search: ababaaaabI found the text "a" starting at index 0 and ending at index 1.I found the text "" starting at index 1 and ending at index 1.I found the text "a" starting at index 2 and ending at index 3.I found the text "" starting at index 3 and ending at index 3.I found the text "a" starting at index 4 and ending at index 5.I found the text "a" starting at index 5 and ending at index 6.I found the text "a" starting at index 6 and ending at index 7.I found the text "a" starting at index 7 and ending at index 8.I found the text "" starting at index 8 and ending at index 8.I found the text "" starting at index 9 and ending at index 9.Enter your regex: a*Enter input string to search: ababaaaabI found the text "a" starting at index 0 and ending at index 1.I found the text "" starting at index 1 and ending at index 1.I found the text "a" starting at index 2 and ending at index 3.I found the text "" starting at index 3 and ending at index 3.I found the text "aaaa" starting at index 4 and ending at index 8.I found the text "" starting at index 8 and ending at index 8.I found the text "" starting at index 9 and ending at index 9.Enter your regex: a+Enter input string to search: ababaaaabI found the text "a" starting at index 0 and ending at index 1.I found the text "a" starting at index 2 and ending at index 3.I found the text "aaaa" starting at index 4 and ending at index 8.

  即使字母“b”在单元格 1、3、8 中出现,但在这些位置上的输出报告了零长度匹配。正则表达式a?不是特意地去寻找字母“b”,它仅仅是去找字母“a”存在或者其中缺少的。如果量词允许匹配“a”零次,任何输入的字符不是“a”时将会作为零长度匹配。在前面的例子中,根据讨论的规则保证了 a 被匹配。
  对于要精确地匹配一个模式 n 次时,可以简单地在一对花括号内指定一个数值:

Enter your regex: a{3}Enter input string to search: aaNo match found.Enter your regex: a{3}Enter input string to search: aaaI found the text "aaa" starting at index 0 and ending at index 3.Enter your regex: a{3}Enter input string to search: aaaaI found the text "aaa" starting at index 0 and ending at index 3.

  这里,正则表确定式a{3}在一行中寻找连续出现三次的字母“a”。第一次测试失败的原由在于,输入的字符串没有足够的 a 用来匹配;第二次测试输出的字符串正好包括了三个“a”,触发了一次匹配;第三次测试也触发了一次匹配,这是由于在输出的字符串的开始部分正好有三个“a”。接下来的事情与第一次的匹配是不相关的,如果这个模式将在这一点后继续出现,那它将会触发接下来的匹配:

Enter your regex: a{3}Enter input string to search: aaaaaaaaaI found the text "aaa" starting at index 0 and ending at index 3.I found the text "aaa" starting at index 3 and ending at index 6.I found the text "aaa" starting at index 6 and ending at index 9.

  对于需要一个模式出现至少 n 次时,可以在这个数字后面加上一个逗号(,):

Enter your regex: a{3,}Enter input string to search: aaaaaaaaaI found the text "aaaaaaaaa" starting at index 0 and ending at index 9.

  输入一样的字符串,这次测试仅仅找到了一个匹配,这是由于一个中有九个“a”满足了“至少”三个“a”的要求。
  最后,对于指定出现次数的上限,可以在花括号添加第二个数字。

Enter your regex: a{3,6} // 寻找一行中至少连续出现 3 个(但不多于 6 个)“a”Enter input string to search: aaaaaaaaaI found the text "aaaaaa" starting at index 0 and ending at index 6.I found the text "aaa" starting at index 6 and ending at index 9.

  这里,第一次匹配在 6 个字符的上限时被迫终止了。第二个匹配包含了剩余的三个 a(这是匹配所允许最小的字符个数)。如果输入的字符串再少掉一个字母,这时将不会有第二个匹配,之后仅剩余两个 a。

5.2 捕获组和字符类中的量词返回目录

  到目前为止,仅仅测试了输入的字符串包括一个字符的量词。实际上,量词仅仅可能附在一个字符后面一次,因此正则表达式abc+的意思就是“a 后面接着 b,再接着一次或者多次的 c”,它的意思并不是指abc一次或者多次。然而,量词也可能附在字符类和捕获组的后面,比如,[abc]+表示一次或者多次的 a 或 b 或 c,(abc)+表示一次或者多次的“abc”组。
  我们来指定(dog)组在一行中三次进行说明。

Enter your regex: (dog){3}Enter input string to search: dogdogdogdogdogdogI found the text "dogdogdog" starting at index 0 and ending at index 9.I found the text "dogdogdog" starting at index 9 and ending at index 18.Enter your regex: dog{3}Enter input string to search: dogdogdogdogdogdogNo match found.

  上面的第一个例子找到了三个匹配,这是由于量词用在了整个捕获组上。然而,把圆括号去掉,这时的量词{3}现在仅用在了字母“g”上,从而导致这个匹配失败。
  类似地,也能把量词应用于整个字符类:

Enter your regex: [abc]{3}Enter input string to search: abccabaaaccbbbcI found the text "abc" starting at index 0 and ending at index 3.I found the text "cab" starting at index 3 and ending at index 6.I found the text "aaa" starting at index 6 and en

给我老师的人工智能教程打call!http://blog.csdn.net/jiangjunshow
这里写图片描述
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值