ZetCode

Java Matcher.results 方法

上次修改时间:2025 年 4 月 20 日

Matcher.results 方法作为 java.util.regex.Matcher 类的一部分,在 Java 9 中引入。它返回正则表达式模式的匹配结果流。此方法提供了一种现代、函数式的正则表达式匹配方法。

与传统的 find 循环不同,results 能够对匹配结果进行流处理。每个匹配结果都表示为一个 MatchResult 对象。该方法特别适用于以声明式风格处理多个匹配结果。

Matcher.results 概述

results 方法扫描输入序列并返回所有找到的匹配结果。它产生一个 MatchResult 对象流。每个对象包含有关单个匹配结果的信息,包括捕获的组。

该方法是非终结操作,这意味着它不会消耗匹配器。您可以在同一个匹配器上多次调用它。但是,在调用之间,匹配器的状态不能被修改。

Matcher.results() 的基本用法

此示例演示了 results 的最简单用法。我们找到字符串中所有单词的出现并打印它们。流处理使代码简洁易读。

BasicResultsExample.java
package com.zetcode;

import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class BasicResultsExample {

    public static void main(String[] args) {
        
        String text = "The quick brown fox jumps over the lazy dog";
        Pattern pattern = Pattern.compile("\\b\\w{4}\\b"); // 4-letter words
        Matcher matcher = pattern.matcher(text);
        
        matcher.results()
               .forEach(mr -> System.out.println("Found: " + mr.group()));
    }
}

在这个例子中,我们编译了一个模式来匹配 4 个字母的单词。results 方法返回一个匹配结果流。我们使用 forEach 来打印每个匹配结果。MatchResultgroup 方法返回匹配的文本。

使用 results 计数匹配结果

results 方法与流操作很好地集成。此示例展示了如何使用流 API 计数匹配结果。这种方法比传统的迭代更简洁。

CountMatchesExample.java
package com.zetcode;

import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class CountMatchesExample {

    public static void main(String[] args) {
        
        String log = "2023-01-01 INFO Start\n2023-01-01 DEBUG Process\n"
                   + "2023-01-02 ERROR Failed\n2023-01-02 INFO Complete";
        Pattern pattern = Pattern.compile("ERROR");
        Matcher matcher = pattern.matcher(log);
        
        long errorCount = matcher.results().count();
        System.out.println("Number of ERROR entries: " + errorCount);
    }
}

在这里,我们搜索日志字符串中的 "ERROR" 条目。results 方法提供了一个可以直接用 count 计数的流。这消除了手动迭代和计数器变量的需要。

提取组信息

MatchResult 对象提供对捕获组的访问。此示例展示了如何从每个匹配结果中提取特定的组信息。我们从字符串中解析日期并以不同的方式格式化它们。

GroupExtractionExample.java
package com.zetcode;

import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class GroupExtractionExample {

    public static void main(String[] args) {
        
        String dates = "2023-05-15, 2024-01-20, 2025-11-30";
        Pattern pattern = Pattern.compile("(\\d{4})-(\\d{2})-(\\d{2})");
        Matcher matcher = pattern.matcher(dates);
        
        matcher.results()
               .map(mr -> String.format("Day: %s, Month: %s, Year: %s", 
                    mr.group(3), mr.group(2), mr.group(1)))
               .forEach(System.out::println);
    }
}

此代码匹配日期字符串并提取它们的组成部分。该模式在单独的组中捕获年、月和日。我们使用 map 来重新格式化每个匹配结果,通过它们的索引访问组。结果是重新格式化的日期字符串的流。

过滤和处理匹配结果

流 API 允许对匹配结果进行复杂的处理。此示例根据组内容过滤匹配结果并执行计算。我们找到并求和字符串中的特定数值。

FilterAndSumExample.java
package com.zetcode;

import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class FilterAndSumExample {

    public static void main(String[] args) {
        
        String data = "A=5, B=3, C=8, A=2, B=7, C=1";
        Pattern pattern = Pattern.compile("([A-C])=(\\d+)");
        Matcher matcher = pattern.matcher(data);
        
        int sumA = matcher.results()
                         .filter(mr -> "A".equals(mr.group(1)))
                         .mapToInt(mr -> Integer.parseInt(mr.group(2)))
                         .sum();
        
        System.out.println("Sum of A values: " + sumA);
    }
}

在这里,我们从字符串中提取键值对。我们只过滤 "A" 值,将它们转换为整数,然后将它们求和。results 与流操作的结合创建了一个强大的数据处理管道。

使用 results 的命名捕获组

命名捕获组使模式更具可读性。此示例演示了如何将命名组与 results 一起使用。我们从格式化的字符串中解析用户信息。

NamedGroupsExample.java
package com.zetcode;

import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class NamedGroupsExample {

    public static void main(String[] args) {
        
        String users = "user:john age:30; user:jane age:25";
        Pattern pattern = Pattern.compile(
            "user:(?<name>\\w+)\\s+age:(?<age>\\d+)");
        Matcher matcher = pattern.matcher(users);
        
        matcher.results()
               .forEach(mr -> System.out.printf(
                   "User %s is %s years old%n",
                   mr.group("name"), mr.group("age")));
    }
}

该模式定义了命名组 "name" 和 "age"。我们在 forEach 操作中按名称访问这些组。命名组通过消除组索引的魔术数字,使代码更易于维护。

匹配结果的并行处理

来自 results 的流可以并行处理。此示例展示了如何利用多核处理器进行正则表达式匹配。我们使用并行流操作处理大量文本。

ParallelProcessingExample.java
package com.zetcode;

import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class ParallelProcessingExample {

    public static void main(String[] args) {
        
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 100; i++) {
            sb.append("item").append(i).append(" ");
        }
        String largeText = sb.toString();
        
        Pattern pattern = Pattern.compile("item\\d+");
        Matcher matcher = pattern.matcher(largeText);
        
        long count = matcher.results()
                           .parallel()
                           .count();
        
        System.out.println("Total items found: " + count);
    }
}

我们生成一个包含许多 "itemN" 模式的大字符串。parallel 调用使匹配结果能够并行处理。这可以显着提高大型输入的性能,尽管不能保证顺序。

将 results() 与其他流操作结合使用

results 与完整的 Java 流 API 集成。此示例展示了高级流操作,例如收集到映射。我们构建文本中单词的频率映射。

StreamOperationsExample.java
package com.zetcode;

import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.stream.Collectors;
import java.util.Map;

public class StreamOperationsExample {

    public static void main(String[] args) {
        
        String text = "apple banana apple cherry banana apple";
        Pattern pattern = Pattern.compile("\\b\\w+\\b");
        Matcher matcher = pattern.matcher(text);
        
        Map<String, Long> wordCounts = matcher.results()
            .collect(Collectors.groupingBy(
                mr -> mr.group().toLowerCase(),
                Collectors.counting()));
        
        System.out.println("Word counts: " + wordCounts);
    }
}

此代码计算字符串中每个单词的出现次数。results 流被收集到一个映射中,其中键是单词,值是计数。这演示了正则表达式匹配如何馈送到复杂的数据处理管道中。

来源

Java Matcher.results() 文档

Matcher.results 方法提供了一种在 Java 中进行正则表达式匹配的现代方法。通过返回匹配结果流,它支持函数式风格的处理,这种处理通常比传统迭代更简洁和更具表达力。

作者

我叫 Jan Bodnar,是一位经验丰富的程序员,在该领域拥有多年的经验。我从 2007 年开始撰写编程文章,此后撰写了 1,400 多篇文章和八本电子书。凭借超过八年的教学经验,我致力于分享我的知识,并帮助他人掌握编程概念。

列出所有Java教程