首页 > Java > java教程 > 正文

Java中利用正则表达式和Stream API从混合字符串中高效提取数字

花韻仙語
发布: 2025-09-25 12:09:13
原创
589人浏览过

java中利用正则表达式和stream api从混合字符串中高效提取数字

本文探讨了如何使用Java中的正则表达式和Stream API,从包含数字、字母和特殊字符的混合文本中提取数字。核心挑战在于,由非空白字符连接的数字应被视为一个整体,而由空白字符分隔的数字则应分别提取。文章详细介绍了两种基于Java 8/9+ Stream API的解决方案:一种利用Matcher.results()进行模式匹配,另一种则通过Pattern.splitAsStream()按空白符分段处理,并提供了相应的代码示例和注意事项。

在处理混合字符串数据时,我们经常需要从中精确地提取出数值信息。本教程将针对一个具体场景,即从包含数字、字母、特殊字符的文本中,按照特定规则(非空白字符连接的数字视为一个整体,空白字符分隔的数字视为独立部分)提取所有数字,提供两种高效的Java实现方案。

1. 方案一:使用 Matcher.results() 进行模式匹配

此方案适用于Java 9及以上版本,它通过一个精心构造的正则表达式直接匹配符合条件的数字序列。

1.1 正则表达式解析

我们需要的正则表达式是 [^\s]*\d+[^\s]*。让我们分解一下它的含义:

  • [^\s]*:匹配零个或多个非空白字符。这允许数字前面可以有字母或特殊字符。
  • \d+:匹配一个或多个数字。这是我们想要提取的核心部分。
  • [^\s]*:再次匹配零个或多个非空白字符。这允许数字后面可以有字母或特殊字符。

这个正则表达式的整体作用是捕获一个包含至少一个数字,且可能被非空白字符包围的完整序列。由于它在遇到空白字符时会停止匹配,因此能够满足“空白字符分隔的数字视为独立部分”的要求。

立即学习Java免费学习笔记(深入)”;

1.2 实现步骤与代码示例

Matcher.results() 方法返回一个 Stream<MatchResult>,其中每个 MatchResult 代表一次成功的匹配。我们可以利用Stream API的链式操作来完成后续的数据清洗和转换。

import java.util.List;
import java.util.regex.MatchResult;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public class NumberExtractor {

    // 匹配包含数字且被非空白字符包围的序列
    public static final Pattern TEXT_WITH_DIGITS_PATTERN = Pattern.compile("[^\s]*\d+[^\s]*");

    /**
     * 从字符串中提取符合特定规则的整数列表。
     * 非空白字符连接的数字被视为一个整体。
     *
     * @param str 待处理的输入字符串。
     * @return 提取到的整数列表。
     */
    public static List<Integer> getIntsUsingMatcherResults(String str) {
        return TEXT_WITH_DIGITS_PATTERN.matcher(str).results() // 获取所有匹配结果的Stream
            .map(MatchResult::group)                           // 提取每个匹配到的完整字符串
            .map(s -> s.replaceAll("\D+", ""))               // 移除字符串中的所有非数字字符
            .map(Integer::valueOf)                             // 将纯数字字符串转换为Integer
            .collect(Collectors.toList());                     // 收集结果到List
    }

    public static void main(String[] args) {
        System.out.println("使用 Matcher.results() 方法:");
        System.out.println("ds[44]%6c -> " + getIntsUsingMatcherResults("ds[44]%6c"));
        System.out.println("2021 ds[44]%6c -> " + getIntsUsingMatcherResults("2021 ds[44]%6c"));
        System.out.println("  abc123def 456 ghi789  -> " + getIntsUsingMatcherResults("  abc123def 456 ghi789  "));
    }
}
登录后复制

1.3 注意事项

  • 此方法要求Java 9或更高版本,因为 Matcher.results() 方法是在Java 9中引入的。
  • replaceAll("\D+", "") 是关键步骤,它确保从捕获到的字符串中只保留数字。\D 匹配任何非数字字符。

2. 方案二:基于 Pattern.splitAsStream() 的分段处理

此方案适用于Java 8及以上版本,它通过将原始字符串按空白字符分割成多个片段,然后对每个片段进行处理。

2.1 分割逻辑解析

首先,我们使用正则表达式 s+ 来分割字符串。s+ 匹配一个或多个空白字符(包括空格、制表符、换行符等)。这样,原始字符串就会被拆分成由非空白字符组成的多个子字符串。

怪兽AI数字人
怪兽AI数字人

数字人短视频创作,数字人直播,实时驱动数字人

怪兽AI数字人 44
查看详情 怪兽AI数字人

2.2 实现步骤与代码示例

Pattern.splitAsStream() 方法返回一个 Stream<String>,其中每个元素是原始字符串中由分隔符分隔的子字符串。

import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public class NumberExtractorSplit {

    // 用于分割字符串的空白字符模式
    public static final Pattern WHITE_SPACES_PATTERN = Pattern.compile("\s+");

    /**
     * 从字符串中提取符合特定规则的整数列表。
     * 先按空白字符分割,再处理每个片段。
     *
     * @param str 待处理的输入字符串。
     * @return 提取到的整数列表。
     */
    public static List<Integer> getIntsUsingSplitAsStream(String str) {
        return WHITE_SPACES_PATTERN.splitAsStream(str) // 按空白字符分割字符串,生成Stream<String>
            .dropWhile(String::isEmpty)                // 移除Stream开头的空字符串(如果输入以空白字符开始)
            .map(s -> s.replaceAll("\D+", ""))        // 移除每个片段中的所有非数字字符
            .filter(s -> !s.isEmpty())                 // 过滤掉处理后可能为空的字符串(例如原始片段只有非数字字符)
            .map(Integer::valueOf)                     // 将纯数字字符串转换为Integer
            .collect(Collectors.toList());             // 收集结果到List
    }

    public static void main(String[] args) {
        System.out.println("使用 Pattern.splitAsStream() 方法:");
        System.out.println("ds[44]%6c -> " + getIntsUsingSplitAsStream("ds[44]%6c"));
        System.out.println("2021 ds[44]%6c -> " + getIntsUsingSplitAsStream("2021 ds[44]%6c"));
        System.out.println("  abc123def 456 ghi789  -> " + getIntsUsingSplitAsStream("  abc123def 456 ghi789  "));
        System.out.println("   -> " + getIntsUsingSplitAsStream("   ")); // 测试全空白字符串
        System.out.println("abc -> " + getIntsUsingSplitAsStream("abc")); // 测试无数字字符串
    }
}
登录后复制

2.3 注意事项

  • 此方法要求Java 8或更高版本。dropWhile() 方法是在Java 9中引入的,但如果不需要处理输入字符串开头为空白字符的情况,或者可以接受一个空字符串作为结果,则在Java 8中可以省略 dropWhile 步骤。对于Java 8,如果需要处理开头空白字符,可能需要先用 trim() 或其他方式处理。
  • filter(s -> !s.isEmpty()) 是一个重要的补充,它用于处理那些在 replaceAll("\D+", "") 之后变为空字符串的片段(例如,原始片段是 "abc" )。
  • Pattern.splitAsStream() 相较于 String.split() 的优势在于它直接生成 Stream,避免了创建中间数组,在处理大量数据时可能更高效。

3. 示例与输出

为了更好地展示两种方法的实际效果,我们统一运行以下测试用例:

public class MainTest {
    public static void main(String[] args) {
        String test1 = "ds[44]%6c";
        String test2 = "2021 ds[44]%6c";
        String test3 = "  abc123def 456 ghi789  ";
        String test4 = "   "; // 全空白字符串
        String test5 = "abc"; // 无数字字符串

        System.out.println("--- 使用 Matcher.results() ---");
        System.out.println("'" + test1 + "' -> " + NumberExtractor.getIntsUsingMatcherResults(test1)); // Output: [446]
        System.out.println("'" + test2 + "' -> " + NumberExtractor.getIntsUsingMatcherResults(test2)); // Output: [2021, 446]
        System.out.println("'" + test3 + "' -> " + NumberExtractor.getIntsUsingMatcherResults(test3)); // Output: [123, 456, 789]
        System.out.println("'" + test4 + "' -> " + NumberExtractor.getIntsUsingMatcherResults(test4)); // Output: []
        System.out.println("'" + test5 + "' -> " + NumberExtractor.getIntsUsingMatcherResults(test5)); // Output: []

        System.out.println("
--- 使用 Pattern.splitAsStream() ---");
        System.out.println("'" + test1 + "' -> " + NumberExtractorSplit.getIntsUsingSplitAsStream(test1)); // Output: [446]
        System.out.println("'" + test2 + "' -> " + NumberExtractorSplit.getIntsUsingSplitAsStream(test2)); // Output: [2021, 446]
        System.out.println("'" + test3 + "' -> " + NumberExtractorSplit.getIntsUsingSplitAsStream(test3)); // Output: [123, 456, 789]
        System.out.println("'" + test4 + "' -> " + NumberExtractorSplit.getIntsUsingSplitAsStream(test4)); // Output: []
        System.out.println("'" + test5 + "' -> " + NumberExtractorSplit.getIntsUsingSplitAsStream(test5)); // Output: []
    }
}
登录后复制

输出结果:

--- 使用 Matcher.results() ---
'ds[44]%6c' -> [446]
'2021 ds[44]%6c' -> [2021, 446]
'  abc123def 456 ghi789  ' -> [123, 456, 789]
'   ' -> []
'abc' -> []

--- 使用 Pattern.splitAsStream() ---
'ds[44]%6c' -> [446]
'2021 ds[44]%6c' -> [2021, 446]
'  abc123def 456 ghi789  ' -> [123, 456, 789]
'   ' -> []
'abc' -> []
登录后复制

4. 总结与选择建议

两种方法都有效地解决了从混合字符串中提取数字的问题,并遵循了特定的分隔规则。

  • Matcher.results() (Java 9+)

    • 优点:正则表达式直接定义了要“捕获”的数字序列模式,逻辑上更直观地表达了“查找符合特定结构的数字组”。
    • 缺点:需要Java 9及以上版本。
    • 适用场景:当提取逻辑主要集中在识别特定模式的数字序列时,此方法更为直接。
  • Pattern.splitAsStream() (Java 8+)

    • 优点:利用空白字符进行分割,将问题分解为更小的、独立的片段处理,对于按分隔符处理的场景非常自然。在Java 8中可用(尽管dropWhile是Java 9特性,但可通过其他方式规避)。
    • 缺点:需要额外处理分割后可能产生的空字符串。
    • 适用场景:当核心问题是根据特定分隔符(如空白符)将字符串分解为多个逻辑单元时,此方法非常高效和简洁。

在实际开发中,您可以根据项目所使用的Java版本、个人偏好以及对代码可读性的考量来选择最合适的方案。两者都展示了Java Stream API在处理集合数据和进行转换方面的强大能力,使得代码更加简洁和富有表达力。

以上就是Java中利用正则表达式和Stream API从混合字符串中高效提取数字的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号