
在处理混合字符串数据时,我们经常需要从中精确地提取出数值信息。本教程将针对一个具体场景,即从包含数字、字母、特殊字符的文本中,按照特定规则(非空白字符连接的数字视为一个整体,空白字符分隔的数字视为独立部分)提取所有数字,提供两种高效的Java实现方案。
此方案适用于Java 9及以上版本,它通过一个精心构造的正则表达式直接匹配符合条件的数字序列。
我们需要的正则表达式是 [^\s]*\d+[^\s]*。让我们分解一下它的含义:
这个正则表达式的整体作用是捕获一个包含至少一个数字,且可能被非空白字符包围的完整序列。由于它在遇到空白字符时会停止匹配,因此能够满足“空白字符分隔的数字视为独立部分”的要求。
立即学习“Java免费学习笔记(深入)”;
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 "));
}
}此方案适用于Java 8及以上版本,它通过将原始字符串按空白字符分割成多个片段,然后对每个片段进行处理。
首先,我们使用正则表达式 s+ 来分割字符串。s+ 匹配一个或多个空白字符(包括空格、制表符、换行符等)。这样,原始字符串就会被拆分成由非空白字符组成的多个子字符串。
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")); // 测试无数字字符串
}
}为了更好地展示两种方法的实际效果,我们统一运行以下测试用例:
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' -> []
两种方法都有效地解决了从混合字符串中提取数字的问题,并遵循了特定的分隔规则。
Matcher.results() (Java 9+):
Pattern.splitAsStream() (Java 8+):
在实际开发中,您可以根据项目所使用的Java版本、个人偏好以及对代码可读性的考量来选择最合适的方案。两者都展示了Java Stream API在处理集合数据和进行转换方面的强大能力,使得代码更加简洁和富有表达力。
以上就是Java中利用正则表达式和Stream API从混合字符串中高效提取数字的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号