Java字符序列替换与分解的四种核心实现方法
在Java开发中,字符串的替换(如剔除数字、格式化文本)与分解(如提取数值、分词)是常见需求。本文总结四种核心实现路径:基于String内置方法的简单处理、StringTokenizer的传统分割、Scanner类型的智能提取,以及Pattern/Matcher的高级正则匹配,并对比其适用场景与效率。
结果或目标:明确文本处理需求
在处理字符序列时,通常需要先确定是将整个字符串中的特定模式替换为新内容,还是将字符串拆分为多个子串,亦或是从中提取特定类型的数据(如整数、浮点数)。不同的目标对应不同的工具选择。
准备条件:理解正则表达式基础
上述多数方法依赖正则表达式(Regex)。常见的符号包括:\d代表数字,\D代表非数字,+ 表示一个或多个前导字符。例如,-?[0-9][0-9]*[.]?[0-9]*可用于匹配包含负数和小数的浮点数或整数。
真实操作顺序
第1步:使用String类进行基础替换与分割
目的:快速执行简单的字符串替换或基于分隔符拆分。
替换操作:调用 replaceAll(String regex, String replacement) 方法。该方法返回新字符串,原字符串不变。所有匹配 regex 的子序列将被替换为 replacement。
String s1 = "123hello456";
// \d+ 匹配一个或多个连续数字
String s2 = s1.replaceAll("\\d+", "你好。");
System.out.println(s2); // 输出: 你好。hello你好。
分割操作:调用 split(String regex) 方法。使用正则作为分隔符将字符串拆分为数组。
String s1 = "1931年9月18日晚,日本发动侵华战争,请记住这个日子!";
// \\D+ 匹配非数字字符作为分隔符
String[] s2 = s1.split("\\D+");
for (String s : s2) {
System.out.println(s); // 分别输出: 1931, 9, 18
}
注意:split 方法在首部分隔符前的空字符串也会计入数组长度。例如 "公元2022年...".split("\\D+"),由于 "公元" 是非数字,它本身作为分隔标记,其左侧的空内容会生成一个空字符串元素 s2[0]="",导致长度为4而非3。
第2步:使用StringTokenizer类进行传统分解
目的:在不支持正则或使用固定分隔符集合时,快速分解单词。此类不依赖正则,而是使用字符集作为分隔标记。
入口:java.util.StringTokenizer。
动作:
- 构造:可使用默认分隔符(空格、换行、Tab等),或通过
StringTokenizer(String s, String delim)指定自定义分隔字符集。注意delim中字符的任意组合均视为分隔符。 - 遍历:调用
hasMoreTokens()检查是否还有内容,循环调用nextToken()获取单词并移除当前指针。 - 计数:可预先调用
countTokens()获取总单词数。
String s = "市话费:28.39元,长途话费:49.15元,上网费:352元";
// 先清洗数据,将非数字和非小数点的字符替换为特殊标记#,方便后续以#分割
String regexDelim = "[^0-9.]+";
s = s.replaceAll(regexDelim, "#");
StringTokenizer fenxi = new StringTokenizer(s, "#");
double totalMoney = 0;
while (fenxi.hasMoreTokens()) {
double money = Double.parseDouble(fenxi.nextToken());
totalMoney += money;
}
System.out.println("总费用:" + totalMoney + "元");
第3步:使用Scanner类进行类型化解析
目的:需要自动转换数据类型(如直接将单词转为 double)且希望节省内存时。
入口:java.util.Scanner。
动作:
- 初始化:将待处理字符串传递给 Scanner 构造函数。
- 设置分隔符:默认以空白字符分隔。调用
useDelimiter(Pattern.compile("你的正则"))或传入字符串形式的正则来改变分隔规则。 - 读取数据:
hasNext()/next():通用字符串读取。hasNextInt()/nextInt()、hasNextDouble()/nextDouble():直接转换为对应类型。若类型不匹配会抛出InputMismatchException,此时需调用next()消耗掉非匹配项以避免死循环。
String cost = "市话费:28.39元,长途话费:49.15元,上网费:352元";
Scanner scanner = new Scanner(cost);
// 指定非数字和小数的任何字符为分隔符
scanner.useDelimiter("[^0-9.]+");
double sum = 0;
while (scanner.hasNext()) {
try {
if (scanner.hasNextDouble()) {
double price = scanner.nextDouble();
sum += price;
System.out.println(price);
} else {
scanner.next(); // 跳过非数字片段
}
} catch (InputMismatchException e) {
scanner.next();
}
}
System.out.println("总费用:" + sum + "元");
第4步:使用Pattern与Matcher类进行高级匹配
目的:需要反复检索、定位索引(start/end)、批量替换或执行复杂的多模式匹配逻辑。
入口:java.util.regex.Pattern 和 java.util.regex.Matcher。
动作:
- 编译模式:调用
Pattern.compile(regex)创建Pattern实例。 - 创建匹配器:调用
pattern.matcher(s)创建Matcher实例。 - 执行检索:
find():查找下一个匹配项。成功则返回 true,并可结合group()获取匹配内容,start()/end()获取位置。matches():判断整个字符串是否完全匹配。lookingAt():判断从字符串开头是否匹配。
- 执行替换:
matcher.replaceAll(替代内容)或matcher.replaceFirst(替代内容)返回新字符串。
String regex = "-?[0-9][0-9]*[.]?[0-9]*";
Pattern pattern = Pattern.compile(regex);
String s = "市话费:28.39元,长途话费:49.15元,上网费:352元";
Matcher matcher = pattern.matcher(s);
double sum = 0;
while (matcher.find()) {
String str = matcher.group();
sum += Double.parseDouble(str);
System.out.println("从 " + matcher.start() + " 到 " + matcher.end() + " 找到: " + str);
}
完成判断与排错
完成判断:程序运行无异常,控制台输出的数值总和与预期一致,或者生成的新字符串符合替换规则。
常见问题:
1. split 导致的数组越界或意外空元素:注意正则边界对空字符串的影响。
2. Scanner 类型不匹配:确保输入序列与读取方法(nextInt/nextDouble)类型一致,否则需手动捕获异常并消费错误标记。
3. 正则性能:对于极长文本的高频替换,预编译的 Pattern 对象比直接在 String 方法中使用字符串正则更高效。
简要总结
String 类适合一次性、简单的替换或分割;StringTokenizer 速度快但功能较旧,适合固定分隔符场景;Scanner 适合流式处理且需自动类型转换的场景,内存占用低;Pattern/Matcher 最灵活强大,适合复杂的正则检索、索引提取及多次复用同一模式。以上就是Java中字符序列替换与分解的详细内容,更多关于Java字符串操作技巧的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













