Pattern(模式):就像一个编译好的“模板”或“规则”,它是一个 final 类,代表一个经过编译的正则表达式,你不会直接创建Pattern实例,而是通过Pattern.compile()静态方法。Matcher(匹配器):像一个“引擎”或“扫描仪”,它使用Pattern这个模板,在一个具体的输入字符串上进行查找、匹配和替换操作。
一个 Pattern 对象可以对应多个 Matcher 对象,每个 Matcher 对象用于处理不同的输入字符串。
核心工作流程
使用 Matcher 的标准三步流程:
- 定义正则表达式:写一个符合正则语法的字符串。
- 编译
Pattern:使用Pattern.compile()将你的正则表达式字符串编译成一个Pattern对象,这一步是高效的,如果要对多个字符串使用同一个正则表达式,只编译一次即可。 - 创建
Matcher:使用pattern.matcher(input)方法,将你的输入字符串和Pattern关联起来,创建一个Matcher实例。 - 执行匹配操作:调用
Matcher的各种方法来执行查找、匹配等操作。
Matcher 的核心方法详解
Matcher 提供了丰富的方法,下面分类介绍最常用的几种。
查找与匹配方法
这些方法用于判断输入字符串中是否存在符合模式的子串。
| 方法 | 描述 | 示例 |
|---|---|---|
boolean find() |
最常用,尝试在输入字符串中查找下一个匹配的子串,找到返回 true,找不到返回 false,可以多次调用,从上次匹配位置的下一个位置开始继续查找。 |
查找字符串中所有出现的 "cat" |
boolean find(int start) |
从指定的索引位置 start 开始,尝试查找下一个匹配的子串。 |
从第 5 个字符开始查找 "cat" |
boolean matches() |
尝试将整个输入字符串与模式匹配,只有当整个字符串完全符合模式时才返回 true。 |
验证一个字符串是否是一个合法的邮箱地址 |
boolean lookingAt() |
尝试从输入字符串的开头开始匹配模式,与 matches() 类似,但它不要求整个字符串都匹配,只要开头部分匹配即可。 |
检查字符串是否以 "http://" 开头 |
获取匹配结果的方法
当 find() 或 matches() 返回 true 后,可以使用这些方法获取匹配到的内容。
| 方法 | 描述 | 示例 |
|---|---|---|
String group() |
返回当前匹配到的整个子串。 | 如果模式是 (\\d+)-(\\d+),匹配 "123-456",group() 返回 "123-456" |
String group(int groupIndex) |
返回指定捕获组匹配到的子串,索引从 1 开始。group(0) 等同于 group()。 |
在 "123-456" 中,group(1) 返回 "123",group(2) 返回 "456" |
int start() |
返回当前匹配子串的起始索引(在输入字符串中的位置)。 | 匹配 "cat" 在 "my cat is cute" 中,start() 返回 3 |
int end() |
返回当前匹配子串的结束索引的下一个位置,即 end() 是 substring(start, end) 的结束索引。 |
匹配 "cat" 在 "my cat is cute" 中,end() 返回 6 |
int start(int groupIndex) |
返回指定捕获组的起始索引。 | 在 "123-456" 中,start(1) 返回 0,start(2) 返回 4 |
int end(int groupIndex) |
返回指定捕获组的结束索引的下一个位置。 | 在 "123-456" 中,end(1) 返回 3,end(2) 返回 7 |
替换方法
| 方法 | 描述 | 示例 |
|---|---|---|
String replaceAll(String replacement) |
替换输入字符串中所有匹配的子串为 replacement 字符串。 |
将字符串中所有 "cat" 替换为 "dog" |
String replaceFirst(String replacement) |
替换输入字符串中第一个匹配的子串为 replacement 字符串。 |
将字符串中第一个 "cat" 替换为 "dog" |
Matcher appendReplacement(StringBuffer sb, String replacement) |
一个更强大的替换方法,用于构建复杂的替换结果,它会将上次匹配到当前匹配之间的文本,以及替换后的文本追加到 StringBuffer 中。 |
通常与 appendTail() 结合使用,实现灵活替换 |
Matcher appendTail(StringBuffer sb) |
在 appendReplacement 之后,将剩余的未匹配部分追加到 StringBuffer 中。 |
完成整个替换过程 |
重置方法
| 方法 | 描述 | 示例 |
|---|---|---|
Matcher reset() |
重置 Matcher 的状态,使其可以重新从输入字符串的开头开始查找。 |
在 find() 循环结束后,如果想重新查找一遍,可以调用此方法 |
Matcher reset(CharSequence input) |
重置 Matcher 并为其设置一个新的输入字符串。 |
复用同一个 Matcher 实例来处理不同的输入 |
代码示例
示例 1:查找所有匹配项并获取捕获组
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class MatcherExample1 {
public static void main(String[] args) {
String text = "John's phone is 123-456-7890, and Jane's is 987-654-3210.";
String regex = "(\\d{3})-(\\d{3})-(\\d{4})"; // 匹配美国电话号码格式
// 1. 编译 Pattern
Pattern pattern = Pattern.compile(regex);
// 2. 创建 Matcher
Matcher matcher = pattern.matcher(text);
System.out.println("查找所有电话号码:");
// 3. 使用 find() 循环查找所有匹配
while (matcher.find()) {
// 获取整个匹配的字符串
System.out.println("找到完整号码: " + matcher.group());
// 获取第一个捕获组 (区号)
System.out.println(" 区号: " + matcher.group(1));
// 获取第二个捕获组 (交换码)
System.out.println(" 交换码: " + matcher.group(2));
// 获取第三个捕获组 (号码)
System.out.println(" 号码: " + matcher.group(3));
System.out.println(" 起始位置: " + matcher.start() + ", 结束位置: " + matcher.end());
System.out.println("--------------------");
}
}
}
输出:
查找所有电话号码:
找到完整号码: 123-456-7890
区号: 123
交换码: 456
号码: 7890
起始位置: 13, 结束位置: 25
--------------------
找到完整号码: 987-654-3210
区号: 987
交换码: 654
号码: 3210
起始位置: 38, 结束位置: 50
--------------------
示例 2:matches() vs lookingAt()
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class MatcherExample2 {
public static void main(String[] args) {
String text1 = "hello world";
String text2 = "hello there, world";
String regex = "hello.*";
Pattern pattern = Pattern.compile(regex);
Matcher matcher1 = pattern.matcher(text1);
Matcher matcher2 = pattern.matcher(text2);
System.out.println("模式: " + regex);
System.out.println("文本1: " + text1);
System.out.println("文本2: " + text2);
System.out.println("\n--- matches() (整个字符串必须匹配) ---");
System.out.println("text1.matches(): " + matcher1.matches()); // true
System.out.println("text2.matches(): " + matcher2.matches()); // false, 因为后面还有 ", world"
System.out.println("\n--- lookingAt() (从开头匹配即可) ---");
System.out.println("text1.lookingAt(): " + matcher1.lookingAt()); // true
System.out.println("text2.lookingAt(): " + matcher2.lookingAt()); // true
}
}
示例 3:替换操作
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class MatcherExample3 {
public static void main(String[] args) {
String text = "apple banana apple orange apple";
String regex = "apple";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(text);
System.out.println("原始文本: " + text);
// replaceAll
String replacedAll = matcher.replaceAll("grape");
System.out.println("replaceAll 结果: " + replacedAll); // grape banana grape orange grape
// reset matcher to use it again
matcher.reset();
// replaceFirst
String replacedFirst = matcher.replaceFirst("grape");
System.out.println("replaceFirst 结果: " + replacedFirst); // grape banana apple orange apple
}
}
重要提示:group(0) vs group()
在 Matcher 中,group(0) 和 group() 完全等价,都代表当前匹配的整个子串,这与一些其他语言(如 Python)的 group(0) 表示整个匹配,而 group() 表示第一个捕获组不同,在 Java 中,group() group(0)。
Pattern是静态的、编译后的规则。Matcher是动态的、用于执行匹配操作的对象。find()是循环查找多个匹配项的核心。matches()用于验证整个字符串格式。group()和group(int)用于提取匹配到的内容,特别是捕获组。replaceAll()和replaceFirst()是最简单的替换方法。
熟练掌握 Matcher 的这些方法,你就可以在 Java 中灵活地处理各种复杂的字符串匹配、提取和替换任务。
