You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修正正则表达式,实现请求日志中cardNo前16位数字掩码

日志cardNo字段掩码方案修正

问题背景

需要对日志中请求的cardNo字段值进行掩码处理,保留最后4位,其余部分替换为X。cardNo的出现形式包含以下场景(冒号两侧可能存在空格):

  • "cardNo":"10929291929312911131"
  • (cardNo:"10929291929312911131",cardType:"CREDIT")
  • "cardNo" : "10929291929312911131"
  • creditCardData(cardNo: "10929291929312911131",cardType:"CREDIT")

修正后的完整代码

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.logging.log4j.core.*;
import org.apache.logging.log4j.core.pattern.LogEventPatternConverter;

@Plugin(name = "LogMaskingConverter", category = "Converter")
@ConverterKeys({ "mask" })
public class LogMaskingConverter extends LogEventPatternConverter {

    // 匹配cardNo的所有出现形式,捕获前缀、掩码部分、最后四位
    private static final Pattern SENSITIVE_DATA_PATTERN = Pattern.compile("(\"?cardNo\"?)\\s*:\\s*\"?(\\d+)(\\d{4})\"?");

    protected LogMaskingConverter(String name, String style) {
        super(name, style);
    }

    public static LogMaskingConverter newInstance(String[] options) {
        return new LogMaskingConverter("mask", null);
    }

    @Override
    public void format(LogEvent event, StringBuilder outputMessage) {
        String message = event.getMessage().getFormattedMessage();
        String maskedMessage;
        try {
            maskedMessage = mask(message);
        } catch (Exception e) {
            maskedMessage = message;
        }
        outputMessage.append(maskedMessage);
    }

    private String mask(String message) {
        StringBuffer buffer = new StringBuffer();
        maskMatcher(SENSITIVE_DATA_PATTERN.matcher(message), buffer);
        return buffer.toString();
    }

    private StringBuffer maskMatcher(Matcher matcher, StringBuffer buffer) {
        while (matcher.find()) {
            String prefix = matcher.group(1);
            String maskedSection = matcher.group(2);
            // 生成与掩码部分等长度的X
            String xReplacement = "X".repeat(maskedSection.length());
            String lastFourDigits = matcher.group(3);
            
            // 保留原格式的引号
            boolean hasQuotes = matcher.group().contains("\"");
            String replacement = prefix + ": ";
            if (hasQuotes) {
                replacement += "\"" + xReplacement + lastFourDigits + "\"";
            } else {
                replacement += xReplacement + lastFourDigits;
            }
            
            matcher.appendReplacement(buffer, replacement);
        }
        matcher.appendTail(buffer);
        return buffer;
    }
}

关键修正说明

  1. 正则表达式修正

    • 正则("?cardNo"?)\s*:\s*"?(\d+)(\d{4})"?:
      • ("?cardNo"?):捕获带/不带引号的cardNo前缀
      • \s*:\s*:匹配冒号两侧任意数量的空格
      • "?(\d+)(\d{4})"?:捕获卡号中除最后4位的部分(\d+)和最后4位(\d{4}),同时兼容卡号带/不带引号的情况
  2. 动态掩码逻辑

    • 不再使用固定数量的X,而是根据卡号需要掩码的部分长度动态生成对应数量的X,适配不同长度的卡号
    • 保留原日志中cardNo字段的引号格式,确保日志格式一致性
  3. 代码语法修正

    • 修正了类继承的拼写错误:extend改为extends
    • 修正了注解拼写错误:ConvertorKeys改为ConverterKeys,category = "Convertor"改为category = "Converter"
    • 修正了newInstance方法中不必要的Thread.currentThread().getName()参数,替换为null符合父类构造要求

内容的提问来源于stack exchange,提问作者kselvan9000

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 15:03:52