导读:本期聚焦于小团团创作的《Java正则表达式怎么在特定模式中部分遮盖字符串并保留末尾N个字符》,敬请观看详情。日志脱敏时常常要把订单号或手机号中间部分遮住只留末四位。直接用字符串截取虽然能实现,但遇到格式不固定或需要按模式匹配的场景就容易出错。正则的replaceAll配合反向引用可以按捕获组把中间段替换成星号,同时保留末尾指定位数。本文说明如何写分组表达式、在替换串里引用分组,以及处理变长字符串和性能注意点,帮助你在脱敏需求中写出稳妥的遮盖逻辑。

在后端服务处理用户敏感数据时,经常需要把特定格式的字符串做部分遮盖,只露出末尾几个字符用于核对。比如内部日志里的银行卡号、提现流水号,如果全量明文打印会有泄露风险,但完全打码又不利于排查问题。用Java正则表达式可以基于模式匹配,精准地把中间一段替换成星号,同时保留末尾N个字符,比手动截取更适应格式变化。

Java正则表达式怎么在特定模式中部分遮盖字符串并保留末尾N个字符

使用捕获组与反向引用实现基础遮盖

核心思路是把原始字符串分成「前面待遮盖部分」和「末尾保留部分」两个捕获组,替换时只把前面组对应的内容换成星号,末尾组原样写回。假设我们要遮盖一个至少八位的数字串,保留最后四位,可以这样写:前面匹配一位或多位数字但不贪婪,末尾四个数字单独成组。

下面示例中,正则表达式 (d+)(d{4}) 把数字拆成两组,替换串用 * 重复前面组的长度并不现实,因此更简单的做法是前面组直接替换为固定数量的星号,或者根据需求用 replaceAll 配合自定义逻辑。若只求视觉遮盖,可用固定星号数。

public class MaskDemo {
    public static void main(String[] args) {
        String input = "6222021234567890123";
        // 保留末尾4位,前面用星号遮盖
        String masked = input.replaceAll("(\d+)(\d{4})", "****$2");
        System.out.println(masked);
    }
}

上面代码里 $2 表示第二个捕获组,也就是末尾四位。运行结果是 ****7890123,达到了保留末四位的效果。这种写法适合长度不固定但末尾位数固定的场景,不需要关心总长多少。

如果希望星号数量和遮盖位数一致,则不能在 replaceAll 的替换串里动态生成星号,需要改用 Matcher 遍历并自己拼装。但多数业务脱敏用固定长度星号已足够,避免过度复杂。

针对复杂格式的模式匹配与分组

真实数据往往带有分隔符或前缀,例如 ORD-20240512-8832 这类订单号,只想遮盖中间日期段而保留前后。此时要用更明确的分组,把不变的前缀、待遮段、保留段分开。通过字符类与量词约束,能防止误伤其他格式字符串。

以下例子保留前缀 ORD- 和末尾四位,中间任意字符遮盖为六个星号。注意正则里用 .*? 非贪婪匹配中间内容,避免跨段吞掉末尾。

public class OrderMask {
    public static void main(String[] args) {
        String order = "ORD-20240512-8832";
        String result = order.replaceAll("(ORD-).*?(-\w{4})", "$1******$2");
        System.out.println(result);
    }
}

这里第一个组 (ORD-) 锁定前缀,第二个组 (-\w{4}) 捕获连字符加末尾四位。替换串写死六个星号,输出为 ORD-******-8832。如果末尾不是固定四位,可以把 \w{4} 改成 \w+ 并用更严谨的边界控制。

当字符串可能包含多种格式时,建议先判断长度或先用 Matcher.matches 试探模式,再决定遮组策略,防止错误遮盖正常文本。对于批量日志处理,可以把正则编译为静态 Pattern 复用,减少重复编译开销。

动态保留N位与性能注意事项

保留末尾N位如果N是变量,无法写死在正则里,需要把N拼进表达式。可以用 String.format 构造 (\d+)(\d{%d}) 这样的模板,再编译Pattern。这样既灵活又保持正则清晰。

下面的方法接收原串和保留位数,返回遮盖结果。它先构建正则,再用 replaceAll 替换。对于超长文本或高频调用,应把Pattern缓存起来而不是每次新建。

import java.util.regex.Pattern;

public class DynamicMask {
    public static String mask(String input, int keepTail) {
        if (input == null || input.length() <= keepTail) {
            return input;
        }
        String regex = "(\d+)(\d{" + keepTail + "})";
        Pattern p = Pattern.compile(regex);
        return p.matcher(input).replaceAll("****$2");
    }

    public static void main(String[] args) {
        System.out.println(mask("6222021234567890123", 4));
        System.out.println(mask("123456", 2));
    }
}

在性能上,正则引擎的回溯可能在极端长串或病态表达式上变慢。尽量用具体字符类代替 .*,并给分组加边界锚点如 ^$ 当整串匹配时。若系统每秒处理数十万条日志,建议对超长串先做长度分流,短串走正则,极长串走手动截取。

另外注意Java字符串不可变,replaceAll 每次生成新对象,在循环里大量遮盖要考虑StringBuilder或char数组手动写,避免频繁GC。正则方案胜在可读与格式适配,手动方案胜在极致性能,按业务量级取舍即可。

Java正则表达式字符串遮盖修改时间:2026-08-18 09:12:19

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。