1、 Java正 则 表 达 式 教 程 1Regular Expressions of Java Tutorial译 者 序正 则 表 达 式 善 于 处 理 文 本 , 对 匹 配 、 搜 索 和 替 换 等 操 作 都 有 意 想 不 到 的 作 用 。 正 因 如 此 , 正则 表 达 式 现 在 是 作 为 程 序 员 七 种 基 本 技 能 之 一 *, 因 此 学 习 和 使 用 它 在 工 作 中 都 能 达 到 很 高的 效 率 。正 则 表 达 式 应 用 于 程 序 设 计 语 言 中 , 首 次 是 出 现 在 Perl 语 言 , 这 也 让 Perl 奠 定 了 正 则
2、 表 达 式 旗 手 的 地 位 。 现 在 , 它 已 经 深 入 到 了 所 有 的 程 序 设 计 语 言 中 , 在 程 序 设 计语 言 中 , 正 则 表 达 式 可 以 说 是 标 准 配 置 了 。Java 中 从 JDK 1.4 开 始 增 加 了 对 正 则 表 达 式 的 支 持 , 至 此 正 则 表 达 式 成 为 了 Java 中 的 基 本 类 库 , 使 用 时 不 需 要 再 导 入 第 三 方 的 类 库 了 。 Java 正 则 表 达 式 的 语 法 来 源 于 象 征 着 正 则 表 达 式 标 准 的 Perl 语 言 , 但 也 不 是 完 全 相
3、 同 的 , 具 体 的 可 以 参 看 Pattern 类 的 API 文 档 说 明 。我 在 一 次 偶 然 中 发 现 了 位 于 站 点 上 的 Java Tutorial, 也 在 那 里 看 到 了 关 于 Java 的 正 则 表 达 式 教 程 , 感 觉 它 不 同 于 其 他 的 正 则 表 达 式 教 程 , 文 中 以 大 量 的 匹 配 实 例 来 进 行 说明 。 为 了 能 让 Java 学 习 者 能 更 好 地 使 用 正 则 表 达 式 , 就 将 其 完 整 地 译 出 了 。 该 教 程 中 所 介 绍 的 正 则 表 达 式 应 用仅 仅 是 最
4、为 简 单 的 ( 并 没 有 完 全 地 涉 及 到 Pattern 类 支 持 的 所 有 正 则 表 达 式 语 法 , 也 没 有 涉 及 到 高 级 的 应 用 ) , 适 合 于 从 未 接 触 过 或 者 是 尚 未完 全 明 白 正 则 表 达 式 基 础 的 学 习 者 。 在 学 习 完 该 教 程 后 , 应 该 对 正 则 表 达 式 有 了 初 步 的 了 解, 并 能 熟 练 地 运 用 java.util.regex 包 中 的 关 于 正 则 表 达 式 的 类 库 , 为 今 后 学 习 更 高 级 的 正 则 表 达 式 技 术 奠 定 良 好 的 基 础
5、。教 程 中 所 有 的 源 代 码 都 在 src 目 录 下 , 可 以 直 接 编 译 运 行 。 由 于 当 前 版 本 的 Java Tutorial 是 基 于 JDK 6.0 的 , 因 此 其 中 的 示 例 程 序 也 用 到 了 JDK 6.0 中 的 新 增 类 库 , 但 正 则 表 达 式 在 JDK 1.4 就 已 经 存 在 了 , 为 了 方 便 大 家 使 用 , 改 写 了 部 分 的 源 代 码 , 源 代 码 类 名 中 后 缀 为 “V4”的 表示 用 于 JDK 1.4 或 以 上 版 本 , “V5”的 表 示 用 于 JDK 5.0 或 以 上
6、版 本 , 没 有 这 些 后 缀 的 类 在 各 个 版 本 中 均 可 以 正 常 使 用 。由 于 译 者 的 水 平 和 技 术 能 力 有 限 , 译 稿 虽 经 多 次 校 对 , 难 免 有 疏 漏 之 处 , 敬 请 大 家 批 评 和 指正 。 若 有 发 现 不 妥 之 处 , 请 发 送 邮 件 至 FrankieG, 我 会 在 blog 中 进 行 勘 误 , 谢 谢 !火 龙 果 顿 首 ! 2008 年 2 月 27 日* 这是由程序员杂志社评出的,刊登在程序员2007 年 3 月刊上。这七种基本技能是:数组,字符串与哈希表、正则表达式、调试、两门语言、一个开发环
7、境、SQL 语言和编写软件的思想。 目 录 译 者 序 序 0 引 言 o 0.1 什 么 是 正 则 表 达 式 ? o 0.2 java.util.regex 包 是 如 何 描 述 正 则 表 达 式 的 ? 1 测 试 用 具 2 字 符 串 o 2.1 元 字 符 3 字 符 类 o 3.1 简 单 类 3.1.1 否 定 3.1.2 范 围 3.1.3 并 集 3.1.4 交 集 3.1.5 差 集 4 预 定 义 字 符 类 5 量 词 o 5.1 零 长 度 匹 配 o 5.2 捕 获 组 和 字 符 类 中 的 量 词 o 5.3 贪 婪 、 勉 强 和 侵 占 量 词 间
8、的 不 同 6 捕 获 组 o 6.1 编 号 方 式 o 6.2 反 向 引 用 7 边 界 匹 配 器 8 Pattern 类 的 方 法 o 8.1 使 用 标 志 构 建 模 式 o 8.2 内 嵌 标 志 表 达 式 o 8.3 使 用 matches(String, CharSequence) 方 法 o 8.4 使 用 split(String) 方 法 o 8.5 其 他 有 用 的 方 法 o 8.6 在 java.lang.String 中 等 价 的 Pattern 方 法 9 Matcher 类 的 方 法 o 9.1 使 用 start 和 end 方 法 o 9.2
9、 使 用 matches 和 lookingAt 方 法 o 9.3 使 用 replaceFirst(String) 和 replaceAll(String) 方 法 o 9.4 使 用 appendReplacement(StringBuffer, String) 和 appendTail(StringBuffer) 方 法 o 9.5 在 java.lang.String 中 等 价 的 Matcher 方 法 10 PatternSyntaxException 类 的 方 法 11 更 多 的 资 源 12 问 题 和 练 习 注 释 译 后 记 序 返 回 目 录本 文 介 绍 如
10、何 使 用 java.util.regex API 作 为 正 则 表 达 式 模 式 匹 配 。 虽 然 说 这 个 包 中 可 被 接 受 的 语 法 参 数 与 Perl 是 相 似 的 , 但 我 们 并 不 需 要 掌 握 Perl 的 语 法 知 识 。 本 教 程 将 从 基 础 开 始 , 逐 层 深 入 到 更 多 的 高 级 技 巧 。 下 面 是 各 章 节 的 主 要 内 容:0 引 言粗 略 地 看 一 下 正 则 表 达 式 , 同 时 也 介 绍 组 成 API 的 核 心 类 。1 测 试 用 具编 写 了 一 个 简 单 的 应 用 程 序 , 用 于 测 试
11、 正 则 表 达 式 的 模 式 匹 配 。2 字 符 串介 绍 基 本 的 模 式 匹 配 、 元 字 符 和 引 用 。3 字 符 类描 述 简 单 字 符 类 、 否 定 、 范 围 、 并 集 、 交 集 和 差 集 。4 预 定 义 字 符 类描 述 空 白 字 符 、 字 母 和 数 字 字 符 等 基 本 的 预 定 义 字 符 。5 量 词使 用 贪 婪 ( greedy) 、 勉 强 ( reluctant) 和 侵 占 ( possessive) 量 词 , 来 匹 配 指 定 表 达 式 X 的 次 数 。6 捕 获 组解 释 如 何 把 多 个 字 符 作 为 一 个
12、单 独 的 单 元 进 行 处 理 。7 边 界 匹 配 器描 述 行 、 单 词 和 输 入 的 边 界 。8 Pattern 类 的 方 法测 试 了 Pattern 中 一 些 有 用 的 方 法 , 以 及 探 究 一 些 高 级 的 特 性 , 诸 如 : 带 标 记 的 编 译 和 使 用 内 嵌 标 记 表 达 式。9 Matcher 类 的 方 法描 述 了 Matcher 类 中 通 常 使 用 的 方 法 。10 PatternSyntaxException 类 的 方 法描 述 了 如 何 检 查 一 个 PatternSyntaxException 异 常 。11 更
13、多 的 资 源要 了 解 更 多 正 则 表 达 式 , 可 以 参 考 这 一 节 。12 问 题 和 练 习巩 固 一 下 本 教 程 所 介 绍 的 正 则 表 达 式 的 基 本 知 识 , 并 附 有 答 案 。为 了 区 分 文 档 中 的 正 则 表 达 式 和 普 通 字 符 串 , 均 以 dabc2的 形 式 表 示 正 则 表 达 式 的模 式 。0 引 言 返 回 目 录0.1 什么是正则表达式?返回目录正 则 表 达 式 ( regular expressions) 是 一 种 描 述 字 符 串 集 的 方 法 , 它 是 以 字 符 串 集 中 各 字 符 串 的
14、 共 有 特 征 为 依 据 的。 正 则 表 达 式 可 以 用 于 搜 索 、 编 辑 或 者 是 操 作 文 本 和 数 据 。 它 超 出 了 Java 程 序 设 计 语 言 的 标 准 语 法 , 因 此 有 必 要 去 学 习 特 定 的 语 法 来 构 建 正 则 表 达 式 。 正 则 表 达 式 的变 化 是 复 杂 的 , 一 旦 你 理 解 了 它 们 是 如 何 被 构 造 的 话 , 你 就 能 解 析 或 者 构 建 任 意 的 正 则 表 达式 了 。本 教 程 讲 授 java.util.regex API 所 支 持 的 正 则 表 达 式 语 法 , 以
15、及 介 绍 几 个 可 运 行 的 例 子 来 说 明 不 同 的 对 象 间 是 如 何 交 互 的 。在 正 则 表 达 式 的 世 界 中 , 有 不 同 风 格 的 选 择 , 比 如 : grep2、 Perl、 Tcl、 Python、 PHP 和 awk。 java.util.regex API 中 的 正 则 表 达 式 语 法 与 Perl 中 的 最 为 相 似 。0.2 java.util.regex 包是如何描述正则表达式的?返回目录java.util.regex 包 主 要 由 三 个 类 所 组 成 : Pattern、 Matcher 和 PatternSynta
16、xException。 Pattern 对 象 表 示 一 个 已 编 译 的 正 则 表 达 式 。 Pattern 类 没 有 提 供 公 共 的 构 造 方 法 。 要 构 建 一 个 模 式 , 首 先 必 须 调 用 公 共 的 静 态 compile 方 法 , 它 将 返 回 一 个 Pattern 对 象 。 这 个 方 法 接 受 正 则 表 达 式 作 为 第 一 个 参 数 。 本 教 程 的 开 始 部 分 将 教 你 必 需 的语 法 。 Matcher 是 一 个 靠 着 输 入 的 字 符 串 来 解 析 这 个 模 式 和 完 成 匹 配 操 作 的 对 象 。
17、 与 Pattern 相 似 , Matcher 也 没 有 定 义 公 共 的 构 造 方 法 , 需 要 通 过 调 用 Pattern 对 象 的 matcher 方 法 来 获 得 一 个 Matcher 对 象 。 PatternSyntaxException 对 象 是 一 个 未 检 查 异 常 , 指 示 了 正 则 表 达 式 中 的 一 个 语 法 错 误 。 本 教 程 的 最 后 几 节 课 程 会 详 细 地 说 明 各 个 类 。 首 当 其 冲 的 问 题 是 : 必 须 理 解 正 则 表 达 式 是 如何 被 构 建 的 , 因 此 下 一 节 引 入 了 一
18、 个 简 单 的 测 试 用 具 , 重 复 地 用 于 探 究 它 们 的 语 法 。 1 测 试 用 具 返 回 目 录这 节 给 出 了 一 个 可 重 用 的 测 试 用 具 RegexTestHarness.java, 用 于 探 究 构 建 API 所 支 持 的 正 则 表 达 式 。 使 用java RegexTestHarness这 个 命 令 来 运 行 , 没 有 被 接 受 的 命 令 行 参 数 。 这 个 应 用 会 不 停 地 循 环 执 行 下 去 3, 提 示 用 户输 入 正 则 表 达 式 和 字 符 串 。 虽 然 说 使 用 这 个 测 试 用 具 是
19、 可 选 的 , 但 你 会 发 现 它 用 于 探 究 下 文所 讨 论 的 测 试 用 例 将 更 为 方 便 。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
20、.“); System.exit(1); 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 e
21、nding 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 中 新 增 的
22、类 库 ( java.io.Console) , 所 以 该 用 具 只 能 在 JDK 6.0 的 环 境 中 编 译 运 行 , 由 于 Console 访 问 操 作 系 统 平 台 上 的 控 制 台 , 因 此 这 个 测 试 用 具 只 能 在 操 作 系 统 的 字 符 控 制 台 中 运 行 , 不能 运 行 在 IDE 的 控 制 台 中 。正 则 表 达 式 是 JDK 1.4 所 增 加 的 类 库 , 为 了 兼 容 JDK 1.4 和 JDK 5.0 的 版 本 , 重 新 改 写 了 这 个 测 试 用 具 , 让 其 能 适 用 于 不 同 的 版 本 。JDK
23、5.0 适 用 的 测 试 用 具 ( RegexTestHarnessV5.java, 该 用 具 可 以 在 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 scanner = new Scanner(System.in);
24、 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 found the text “%s“ start
25、ing 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) :import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.IOExcep
26、tion; 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 (t
27、rue) System.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
28、 at index “ + matcher.start() + “ and ending at index “ + matcher.end() + “.“); found = true; if (!found) System.out.println(“No match found.“); 2 字 符 串 返 回 目 录在 大 多 数 的 情 况 下 , API所 支 持 模 式 匹 配 的 基 本 形 式 是 匹 配 字 符 串 , 如 果 正 则 表 达 式 是 foo, 输 入 的 字 符 串 也 是 foo, 这 个 匹 配 将 会 是 成 功 的 , 因 为 这 两 个 字 符 串 是
29、 相 同 的 。 试 着 用 测 试 用 具 来 测 试 一 下 : 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。 这 个 是 约 定 俗 成 的 , 范 围 包 括 开 始 的 索 引 , 不 包 括 结 束 的 索 引 , 如
30、下 图 所 示 :图 1 字 符 串 “foo”的 单 元 格 编 号 和 索 引 值 4字 符 串 中 的 每 一 个 字 符 位 于 其 自 身 的 单 元 格 ( cell) 中 , 在 每 个 单 元 格 之 间 有 索 引 指 示 位 。字 符 串 “foo”始 于 索 引 0 处 , 止 于 索 引 3 处 , 即 使 是 这 些 字 符 它 们 自 己 仅 占 据 了 0、 1 和 2 号 单 元 格 。就 子 序 列 匹 配 而 言 , 你 会 注 意 到 一 些 重 叠 , 下 一 次 匹 配 开 始 索 引 与 前 一 次 匹 配 的 结 束 索 引 是相 同 的 :Ent
31、er 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 也 支 持 许 多 可 以 影 响 模 式 匹 配 的 特 殊
32、字 符 。 把 正 则 表 达 式 改 为 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) ( 被 这 个 匹 配 翻 译 成
33、了 具 有 特 殊 意 义 的 字 符 了 ) 。 这 个 例 子 为 什 么能 匹 配 成 功 的 原 因 在 于 , 元 字 符 .指 的 是 “任 意 字 符 ”。API 所 支 持 的 元 字 符 有 : (-$|)?*+. 注 意 : 在 学 习 过 更 多 的 如 何 构 建 正 则 表 达 式 后 , 你 会 碰 到 这 些 情 况 : 上 面 的 这 些 特 殊 字 符不 应 该 被 处 理 为 元 字 符 。 然 而 也 能 够 使 用 这 个 清 单 来 检 查 一 个 特 殊 的 字 符 是 否 会 被认 为 是 元 字 符 。 例 如 , 字 符 !、 和 # 决 不
34、会 有 特 殊 的 意 义 。 有 两 种 方 法 可 以 强 制 将 元 字 符 处 理 成 为 普 通 字 符 :1. 在 元 字 符 前 加 上 反 斜 线 ( ) ;2. 把 它 放 在 Q( 引 用 开 始 ) 和 E( 引 用 结 束 ) 之 间 5。 在 使 用 这 种 技 术 时 , Q和 E能 被 放 于表 达 式 中 的 任 何 位 置 ( 假 设 先 出 现 Q6)3 字 符 类 返 回 目 录如 果 你 曾 看 过 Pattern 类 的 说 明 , 会 看 到 一 些 构 建 正 则 表 达 式 的 概 述 。 在 这 一 节 中 你 会 发 现 下 面 的 一 些
35、表 达 式 :字 符 类abc a, b 或 c( 简 单 类 )abc除 a, b 或 c 之 外 的 任 意 字 符 ( 取 反 )a-zA-Z a 到 z, 或 A 到 Z, 包 括 ( 范 围 )a-dm-pa 到 d, 或 m 到 p: a-dm-p( 并 集 )a-z / 单 个 数 字这 个 例 子 中 d是 正 则 表 达 式 , 另 外 的 那 个 反 斜 线 是 用 于 代 码 编 译 所 必 需 的 。 但 是 测 试 用 具读 取 的 表 达 式 , 是 直 接 从 控 制 台 中 输 入 的 , 因 此 不 需 要 那 个 多 出 来 的 反 斜 线 。下 面 的 例
36、 子 说 明 了 预 字 义 字 符 类 的 用 法 :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:
37、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
38、 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.Ent
39、er 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 re
40、gex: 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.在 开 始 的 三 个 例 子 中 , 正 则 表 达 式 是 简 单 的 , .( “点 ”元 字 符 ) 表 示 “任 意 字 符 ”,
41、 因 此 , 在所 有 的 三 个 例 子 ( 随 意 地 选 取 了 “”字 符 , 数 字 和 字 母 ) 中 都 是 匹 配 成 功 的 。 在 接 下 来 的 例子 中 , 都 使 用 了 预 定 义 字 符 类 表 格 中 的 单 个 正 则 表 达 式 构 造 。 你 应 该 可 以 根 据 这 张 表 指 出 前面 每 个 匹 配 的 逻 辑 :d 匹 配 数 字 字 符s 匹 配 空 白 字 符w 匹 配 单 词 字 符也 可 以 使 用 意 思 正 好 相 反 的 大 写 字 母 :D 匹 配 非 数 字 字 符S 匹 配 非 空 白 字 符W 匹 配 非 单 词 字 符5
42、量 词 返 回 目 录这 一 节 我 们 来 看 一 下 贪 婪 ( greedy) 、 勉 强 ( reluctant) 和 侵 占 ( possessive) 量 词 , 来 匹配 指 定 表 达 式 X的 次 数 。量 词 ( quantifiers) 允 许 指 定 匹 配 出 现 的 次 数 , 方 便 起 见 , 当 前 Pattern API 规 范 下 , 描 述 了 贪 婪 、 勉 强 和 侵 占 三 种 量 词 。 首 先 粗 略 地 看 一 下 , 量 词 X?、 X?和 X?+都 允许 匹 配 X 零 次 或 一 次 , 精 确 地 做 同 样 的 事 情 , 但 它
43、们 之 间 有 着 细 微 的 不 同 之 处 , 在 这 节 结 束 前 会 进 行说 明 。量 词 种 类 意 义贪 婪 勉 强 侵 占X? X? X?+匹 配 X 零 次 或 一 次X* X*? X*+匹 配 X 零 次 或 多 次X+ X+? X+匹 配 X 一 次 或 多 次Xn Xn? Xn+ 匹 配 X n 次Xn, Xn,? Xn,+ 匹 配 X 至 少 n 次Xn,m Xn,m? Xn,m+匹 配 X 至 少 n 次 , 但 不 多 于 m 次那 我 们 现 在 就 从 贪 婪 量 词 开 始 , 构 建 三 个 不 同 的 正 则 表 达 式 : 字 母 a后 面 跟 着
44、?、 *和 +。 接下 来 看 一 下 , 用 这 些 表 达 式 来 测 试 输 入 的 字 符 串 是 空 字 符 串 时 会 发 生 些 什 么 :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.E
45、nter your regex: a+Enter input string to search: No match found.5.1 零长度匹配 返回目录在 上 面 的 例 子 中 , 开 始 的 两 个 匹 配 是 成 功 的 , 这 是 因 为 表 达 式 a?和 a*都 允 许 字 符 出 现 零 次。 就 目 前 而 言 , 这 个 例 子 不 像 其 他 的 , 也 许 你 注 意 到 了 开 始 和 结 束 的 索 引 都 是 0。 输 入 的 空 字 符 串 没 有 长 度 , 因 此 该 测 试 简 单 地 在 索 引 0 上 匹 配 什 么 都 没 有 , 诸 如 此 类
46、的 匹 配 称 之 为 零 长 度 匹 配 ( zero-length matches) 。 零 长 度 匹 配 会 出 现 在 以 下 几 种 情 况 : 输 入 空 的 字 符 串 、 在 输 入 字 符 串 的 开 始 处、 在 输 入 字 符 串 最 后 字 符 的 后 面 , 或 者 是 输 入 字 符 串 中 任 意 两 个 字 符 之 间 。 由 于 它 们 开 始 和结 束 的 位 置 有 着 相 同 的 索 引 , 因 此 零 长 度 匹 配 是 容 易 被 发 现 的 。我 们 来 看 一 下 关 于 零 长 度 匹 配 更 多 的 例 子 。 把 输 入 的 字 符 串
47、改 为 单 个 字 符 “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 a
48、t 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 处 找 到 了 零 长 度 匹 配 , 也 就 是 说 , 在 输 入
49、字 符 串 最 后 一 个 字 符 的 后 面 。 回 想 一 下 , 匹 配 把 字符 “a”看 作 是 位 于 索 引 0 和 索 引 1 之 间 的 单 元 格 中 , 并 且 测 试 用 具 一 直 循 环 下 去 直 到 不 再 有 匹 配 为 止 。 依 赖 于 所 使 用 的 量 词 不同 , 最 后 字 符 后 面 的 索 引 “什 么 也 没 有 ”的 存 在 可 以 或 者 不 可 以 触 发 一 个 匹 配 。现 在 把 输 入 的 字 符 串 改 为 一 行 5 个 “a”时 , 会 得 到 下 面 的 结 果 :Enter your regex: a?Enter inp