Java 字符串替换
String类内置了多种替换方法,同时也支持正则表达式、批量替换等进阶操作。本文从基础方法到复杂场景,拆解字符串替换的核心用法与避坑要点。
一、核心替换方法:replace /replaceAll/replaceFirst
String 类提供了 3 个核心替换方法,三者的核心区别在于是否支持正则表达式、替换范围,具体对比如下:| 方法名 | 匹配规则 | 替换范围 | 核心特点 |
|---|---|---|---|
replace() |
普通字符 / 字符串 | 所有匹配项 | 不支持正则,性能高 |
replaceAll() |
正则表达式 | 所有匹配项 | 支持复杂正则,需注意转义 |
replaceFirst() |
正则表达式 | 第一个匹配项 | 仅替换首次出现的匹配内容 |
1. 基础替换:replace ()(无正则,最常用)
replace() 有两个重载版本:replace(char oldChar, char newChar):替换所有指定字符;replace(CharSequence target, CharSequence replacement):替换所有指定字符串。
public class StringReplaceDemo {public static void main(String[] args) {String str = "Java is easy, Java is fun";// 替换所有字符'a'为'A'String result = str.replace('a', 'A');System.out.println(result); // 输出:JAva is eAsy, JAva is fun}
}
public class StringReplaceDemo {public static void main(String[] args) {String str = "2025-12-10";// 替换所有"-"为"/"(即使传类似正则的字符串,也会当作普通文本)String result = str.replace("-", "/");System.out.println(result); // 输出:2025/12/10}
}
关键注意:replace()不解析正则表达式!比如传入replace(".", "*"),会替换所有.字符,而非正则中的 “任意字符”。
2. 正则替换:replaceAll ()(匹配所有)
replaceAll() 支持正则表达式匹配,适合复杂规则的替换(如数字脱敏、格式转换)。public class StringReplaceDemo {public static void main(String[] args) {String phone = "手机号:13812345678";// 正则匹配所有数字(\\d),替换为*String maskedPhone = phone.replaceAll("\\d", "*");System.out.println(maskedPhone); // 输出:手机号:***********}
}
public class StringReplaceDemo {public static void main(String[] args) {String date = "2025-12-10";// 正则分组:(\d{4})匹配年,(\d{2})匹配月,(\d{2})匹配日,$1/$2/$3引用分组String newDate = date.replaceAll("(\\d{4})-(\\d{2})-(\\d{2})", "$1/$2/$3");System.out.println(newDate); // 输出:2025/12/10}
}
.表示 “任意字符”,若需替换普通.,需用\\.转义,或用Pattern.quote()包裹目标字符串:public class StringReplaceDemo {public static void main(String[] args) {String str = "www.baidu.com";// 错误:.匹配任意字符,会替换所有字符为-// String wrong = str.replaceAll(".", "-"); // 正确:转义.,替换所有.为-String correct1 = str.replaceAll("\\.", "-");// 更安全:用Pattern.quote()自动转义String correct2 = str.replaceAll(Pattern.quote("."), "-");System.out.println(correct1); // 输出:www-baidu-comSystem.out.println(correct2); // 输出:www-baidu-com}
}
3. 局部替换:replaceFirst ()(仅替换第一个匹配项)
public class StringReplaceDemo {public static void main(String[] args) {String str = "a1b2c3d4";// 仅替换第一个数字为*String result = str.replaceFirst("\\d", "*");System.out.println(result); // 输出:a*b2c3d4// 替换首个逗号为分号String text = "苹果,香蕉,橙子,葡萄";String textResult = text.replaceFirst(",", ";");System.out.println(textResult); // 输出:苹果;香蕉,橙子,葡萄}
}
二、进阶场景:复杂替换需求
场景 1:忽略大小写替换
AbC/ABC/abc都替换为xyz),可借助正则的(?i)标记(忽略大小写):public class StringReplaceDemo {public static void main(String[] args) {String str = "AbC123abc456ABC";// (?i)标记忽略大小写,替换所有abc为xyzString result = str.replaceAll("(?i)abc", "xyz");System.out.println(result); // 输出:xyz123xyz456xyz}
}
场景 2:模板参数批量替换
Map+ 循环实现:import java.util.HashMap;
import java.util.Map;public class TemplateReplaceDemo {public static void main(String[] args) {// 模板字符串String template = "您好,{name}!您的订单{orderId}已发货,预计{date}送达。";// 替换规则Map<String, String> params = new HashMap<>();params.put("{name}", "张三");params.put("{orderId}", "JD12345678");params.put("{date}", "2025-12-15");// 批量替换String result = template;for (Map.Entry<String, String> entry : params.entrySet()) {result = result.replace(entry.getKey(), entry.getValue());}System.out.println(result);// 输出:您好,张三!您的订单JD12345678已发货,预计2025-12-15送达。}
}
进阶优化:高频模板替换可使用 Apache Commons Text 的StrSubstitutor,简化代码:// 需引入依赖:org.apache.commons:commons-text:1.10.0 StrSubstitutor substitutor = new StrSubstitutor(params); String result = substitutor.replace(template);
场景 3:批量替换多个关键词
Map存储替换规则,循环调用replace():import java.util.HashMap;
import java.util.Map;public class MultiReplaceDemo {public static void main(String[] args) {String content = "这是垃圾内容,包含脏话!";Map<String, String> sensitiveWords = new HashMap<>();sensitiveWords.put("垃圾", "**");sensitiveWords.put("脏话", "##");String cleanContent = content;for (Map.Entry<String, String> entry : sensitiveWords.entrySet()) {cleanContent = cleanContent.replace(entry.getKey(), entry.getValue());}System.out.println(cleanContent); // 输出:这是**内容,包含##!}
}
场景 4:空值 / 空字符串处理
public class EmptyReplaceDemo {public static void main(String[] args) {String str = ""; // 空字符串String nullStr = null; // null// 替换空字符串为默认值String result1 = str.isEmpty() ? "默认值" : str;System.out.println(result1); // 输出:默认值// 替换null为默认值String result2 = nullStr == null ? "默认值" : nullStr;System.out.println(result2); // 输出:默认值// 注意:replace("", "x")会在每个字符间插入x(慎用)String test = "abc";System.out.println(test.replace("", "x")); // 输出:xa xb xc x(实际是xaxbxcx)}
}
三、避坑指南:常见错误与解决方案
1. 忽略 String 不可变性
String是不可变对象,所有替换方法都会返回新字符串,原字符串不会改变,必须接收返回值 // 错误示例:未接收返回值,原字符串不变
String str = "abc";
str.replace('a', 'x');
System.out.println(str); // 输出:abc// 正确示例:接收返回值
String newStr = str.replace('a', 'x');
System.out.println(newStr); // 输出:xbc
2. 正则特殊字符未转义
replaceAll()/replaceFirst()时,若目标字符串包含.*+?|()[]{}^$等正则特殊字符,未转义会导致替换结果异常:// 错误:|在正则中是“或”,会把"a|b"拆分为"a"或"b"
String str = "a|b|c";
String wrong = str.replaceAll("a|b", "*");
System.out.println(wrong); // 输出:*|*|c// 正确:用Pattern.quote()转义
String correct = str.replaceAll(Pattern.quote("a|b"), "*");
System.out.println(correct); // 输出:*|c
3. 频繁替换导致性能问题
String的不可变性会创建大量临时对象,建议改用StringBuilder:// 低效:多次创建String对象
String str = "a1b2c3d4";
for (int i = 0; i < 10; i++) {str = str.replace(String.valueOf(i), "*");
}// 高效:使用StringBuilder
StringBuilder sb = new StringBuilder("a1b2c3d4");
for (int i = 0; i < 10; i++) {int index = sb.indexOf(String.valueOf(i));while (index != -1) {sb.replace(index, index+1, "*");index = sb.indexOf(String.valueOf(i), index+1);}
}
String result = sb.toString();
System.out.println(result); // 输出:a*b*c*d*
4. 空指针异常(NPE)
public static String safeReplace(String str, String oldStr, String newStr) {if (str == null || oldStr == null || newStr == null) {return str; // 或返回默认值}return str.replace(oldStr, newStr);
}
四、实战案例:数据脱敏(手机号 + 身份证号)
public class DataMaskDemo {// 手机号脱敏:保留前3后4,中间替换为****public static String maskPhone(String phone) {if (phone == null || !phone.matches("\\d{11}")) {return phone; // 非11位手机号直接返回}return phone.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");}// 身份证号脱敏:保留前6后4,中间替换为**********public static String maskIdCard(String idCard) {if (idCard == null || idCard.length() != 18) {return idCard; // 非18位身份证直接返回}return idCard.replaceAll("(\\d{6})\\d{8}(\\d{4})", "$1**********$2");}public static void main(String[] args) {System.out.println(maskPhone("13812345678")); // 输出:138****5678System.out.println(maskIdCard("110101199001011234")); // 输出:110101**********1234}
}
五、总结
- 简单替换(字符 / 固定字符串):用
replace(),性能高且无需考虑正则; - 复杂规则替换(正则匹配):用
replaceAll()/replaceFirst(),注意特殊字符转义; - 批量 / 模板替换:结合
Map循环或第三方库(如 Apache Commons Text); - 高频替换:优先用
StringBuilder提升性能,避免频繁创建 String 对象。
相关新闻
2025年上海离婚房产律所权威推荐榜单:婚姻律所/继承律所/房产律所解决方案优选 - 品牌推荐官
随着近年来家庭资产结构的深刻变化,房产已成为绝大多数家庭最核心的资产。在离婚案件中,涉及房产分割争议的比例已超过七成,此类纠纷因其法律关系的复杂性、财产价值的高昂性以及证据梳理的繁琐性,对专业法律服务提…
综合安防数智管理平台
在数字化转型浪潮下,安防已从单一的视频监控演变为覆盖视频、报警、门禁、巡更、车辆管理等多元系统的综合体系。综合安防数智管理平台正是这一演进的核心载体——它通过统一的软件平台,把原本分散的安防子系统深度融…
医疗屏蔽房生产厂家哪家口碑好、实力强、信誉好? - 工业推荐榜
本榜单依托电磁防护设备领域全维度市场调研与医疗行业真实客户口碑,深度筛选出十家标杆企业,为医疗机构、科研院所及军工单位选型提供客观依据,助力精准匹配适配的医疗屏蔽解决方案伙伴。 TOP1 推荐:常州硕捷屏蔽设…
最新新闻
鸿蒙原生开发手记:徒步迹 - 自定义地图标记与气泡弹窗
鸿蒙原生开发手记:徒步迹 - 自定义地图标记与气泡弹窗打造个性化地图交互,提升用户体验一、前言 默认的地图标记样式单一,不能满足 App 的品牌需求。本文介绍如何实现自定义地图标记图标和气泡弹窗(InfoWindow)&#x…
鸿蒙原生开发手记:徒步迹 - 首页布局设计与Scroll滚动
鸿蒙原生开发手记:徒步迹 - 首页布局设计与Scroll滚动使用 Scroll 和 ForEach 构建可滚动的首页一、前言 首页是 App 的门面,需要展示丰富的信息同时保持良好的浏览体验。徒步迹的首页包括:今日概览、快捷功能入口、推荐路线三大模块。 本文详…
如何快速在OpenEuler上安装Qt6:5分钟搭建跨平台GUI开发环境
如何快速在OpenEuler上安装Qt6:5分钟搭建跨平台GUI开发环境 【免费下载链接】qt6 Qt6 meta package 项目地址: https://gitcode.com/openeuler/qt6 前往项目官网免费下载:https://ar.openeuler.org/ar/ 想要在OpenEuler上快速搭建跨平台GUI开发环…
鸿蒙原生开发手记:徒步迹 - 登录注册页面与表单校验
鸿蒙原生开发手记:徒步迹 - 登录注册页面与表单校验实现完整的用户认证流程,包含表单验证和交互反馈一、前言 登录注册是绝大多数 App 的入口功能。本文实现“徒步迹“的登录注册页面,包含手机号输入、密码输入、表单校验、Loading 状态等完整…
写网文卡文缺灵感?全流程 AI 辅助工具分层搭配,新手全职作者通用(2026年新版)
导语随着人工智能技术持续落地文创领域,AI 辅助写作逐步成为网文作者、传统文学创作者、编剧以及非虚构书籍撰稿人的日常创作方式。当下市场涌现出多款主打 AI 智能写作的工具产品,各类产品在功能侧重、技术架构、服务定价、适配创作题材上分化明显&…
2026年现阶段苏州代账公司会计团队选择趋势与专业推荐 - 品牌鉴赏官2026
在当前经济环境下,企业的精细化运营与合规性要求日益提升。2026年现阶段,对于苏州地区的中小微企业而言,一个专业、稳定、的会计团队不仅是处理账务的“后盾”,更是企业规避风险、规划财税、乃至辅助决策的“战略伙…
日新闻
VS Code 高效配置与个性化定制全攻略
1. VS Code 高效配置基础作为一款轻量级但功能强大的代码编辑器,VS Code 的默认配置已经能满足基本需求,但通过合理调整设置可以大幅提升编码效率。我使用 VS Code 已经有五年多时间,期间尝试过各种配置方案,总结出这套适合大多数…
从竞赛代码到桌面工具:让 SuperADD 与 SubspaceAD 真正跑进自己的图像
在异常检测领域,很多优秀算法最初都是以研究代码的形式发布的。它们能够在固定测试集上复现实验结果,却不一定能被普通用户直接拿来测试自己的图片。尤其是最近很多算法仅提供在固定测试集的测试环境,而gradio的demo演示也不会提供。 对工程应用和在自己的图片上进行测试来…
WinRAR高效配置指南:从基础安装到高级压缩实战
前几天帮同事处理一个客户发来的压缩包,解压时系统自带的工具弹出一串乱码,换用 WinRAR 却顺利打开了。这种看似简单的场景,恰恰暴露了不同压缩工具在处理非标准编码、分卷压缩或加密文件时的差异。WinRAR 作为一款老牌工具,真正价…
周新闻
PlantUML 实战:5分钟将 UML 2.5 序列图转换为可执行代码草图
PlantUML 实战:5分钟将 UML 2.5 序列图转换为可执行代码草图 在软件开发过程中,清晰的系统设计往往比编码本身更为关键。传统拖拽式UML工具虽然直观,却常常成为效率杀手——频繁的鼠标操作打断设计思路,版本控制困难,…
【RT-DETR涨点改进】29 动态Batch推理:让RT-DETR在低延迟下吃满GPU算力
29 动态Batch推理:让RT-DETR在低延迟下吃满GPU算力 开篇故事 上个月帮一家安防厂商做项目优化,他们用RT-DETR做实时人流统计,部署在NVIDIA A10上。客户反馈说:“GPU利用率才30%,但延迟已经飙到40ms了,加人流量就丢帧。” 我远程一看,好家伙——生产环境里每个请求单独…
Postman 环境变量实战:3种动态设置方法与CI/CD集成避坑指南
Postman 环境变量高阶实战:动态管理与 CI/CD 深度集成在接口自动化测试领域,环境变量的灵活运用往往成为区分初级与高级测试工程师的关键能力。本文将深入探讨 Postman 环境变量的三种动态设置模式,并分享 Newman 在 CI/CD 流水线中的实战避坑…
月新闻
[C++]内存管理:串顺序存储的内存回收
在串(字符串)的顺序存储中,内存回收的方式取决于字符串的存储方式以及所使用的编程语言和相关库。以下以 C 为例进行说明,因为 C 对内存管理有较为直接的控制。 1. 基于 char 数组的串顺序存储 如果使用普通的 char 数组来存储字…
移动端游戏功耗测试实战:电流、功率、亮度和场景对比
移动端游戏功耗测试:先控制变量,再比较优化是否真的省电 摘要:功耗测试最容易犯的错误,是拿两次不同温度、不同亮度、不同场景的平均功率直接比较。本文给出一套可复现的游戏功耗测试方法,覆盖引擎特性验证、版本回归和黑盒体验测试,并说明如何把功耗与帧率、温控、CPU/G…
足球口袋教练 HarmonyOS 离线应用实战(03/20):ArkUI 首页仪表盘搭建
本文是“足球口袋教练 HarmonyOS 离线应用实战”系列第 3 篇。示例项目是一个 HarmonyOS / ArkTS / ArkUI 编写的离线足球训练助手,围绕真实页面、真实截图和可复现操作展开。 本篇要解决的问题 训练 App 的首页不能只展示欢迎语,它要解决“我现在该点哪…