
本文介绍如何精准移除 JSON 对象中键名末尾以 # 分隔的冗余标识符(如 DynamicAttribute#1279930005#ZZ8400 → DynamicAttribute),避免破坏整体结构,重点讲解基于 Jackson 的安全字符串替换策略与正则设计要点。
本文介绍如何精准移除 json 对象中键名末尾以 `#` 分隔的冗余标识符(如 `dynamicattribute#1279930005#zz8400` → `dynamicattribute`),避免破坏整体结构,重点讲解基于 jackson 的安全字符串替换策略与正则设计要点。
在处理外部系统传入的 JSON 数据时,常遇到键名携带动态哈希或时间戳后缀的情况(例如 DynamicAttribute#1279930005#ZZ8400)。这类后缀通常用于唯一性标识,但在业务逻辑中无需保留,需清洗为语义清晰的原始键名(如 DynamicAttribute)。直接对整个 JSON 字符串执行 replaceAll 是高危操作——它可能误删值中的 #(如注释、URL 或字符串字段),或破坏 JSON 结构(如你示例中丢失了外层字段)。
✅ 正确做法是:仅针对目标子节点(如 "values" 对象)进行键名标准化,而非全文本暴力替换。由于 Jackson 的 JsonNode 不支持直接修改键名,推荐采用「提取 → 重建」策略,或对序列化后的子对象字符串做上下文受限的正则替换。
✅ 推荐方案:精准正则 + 子节点局部处理
若确定 "values" 中所有键均符合 Key#Number#Code 模式(如 DynamicAttribute#1279930005#ZZ8400),可使用以下正则安全清理:
// 匹配 # + 字母数字 + # + 字母数字(贪婪,覆盖常见格式)
String cleanedValuesJson = objectNode.toString().replaceAll("#\w+#\w+", "");
该正则 #\w+#\w+ 含义:
- # :字面量井号
- \w+ :匹配一个及以上字母、数字或下划线(等价于 [a-zA-Z0-9_])
- #\w+ :第二个 # 及其后缀
⚠️ 注意:此正则假设后缀均为 w+ 形式。若实际包含短横线(-)、点号(.)等,需扩展为 #[\w-]+#[\w-]+。
? 完整可运行示例(JUnit 测试)
@Test
void cleanJsonValueKeys() throws JsonProcessingException {
String eventData = """
{
"uniqueCode": "ZZ",
"entity": "PROFILE",
"id": "e2b627b360d664377b227b--70378143#1",
"data": ["DynamicAttribute"],
"values": {
"DynamicAttribute#1279930005#ZZ8400": [{
"property": "activeFlag",
"currentState": true,
"previousState": null
}]
},
"DATE_TIME": "05-Apr-2023 19:17:14.376"
}
""";
ObjectMapper mapper = new ObjectMapper();
JsonNode root = mapper.readTree(eventData);
ObjectNode valuesNode = mapper.convertValue(root.get("values"), ObjectNode.class);
// ✅ 安全清洗:仅作用于 values 子树的序列化字符串
String cleaned = valuesNode.toString().replaceAll("#\w+#\w+", "");
// cleaned → {"DynamicAttribute":[{"property":"activeFlag","currentState":true,"previousState":null}]}
// ✅ 可选:将清洗后的 JSON 重新注入原结构(保持完整性)
ObjectNode updatedRoot = (ObjectNode) root;
updatedRoot.set("values", mapper.readTree(cleaned));
System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(updatedRoot));
}
⚠️ 关键注意事项
- 绝不全局替换:避免 eventData.replaceAll(...),否则会污染 id、DATE_TIME 等字段中的合法 #。
- 优先考虑键名重构:更健壮的方式是遍历 valuesNode.fields(),用 entry.getKey().replaceFirst("#\w+#\w+$", "") 提取新键,再构建新 ObjectNode —— 避免字符串解析风险。
- 正则边界控制:添加 $ 锚点(#\w+#\w+$)确保只匹配键尾后缀,防止误伤中间 #(如 "url": "https://example.com#section")。
- 空格与转义:JSON 序列化默认不带多余空格,若输入含格式化空格,建议先 mapper.configure(JsonGenerator.Feature.ESCAPE_NON_ASCII, true) 统一处理。
通过聚焦子节点、限定正则范围、验证输出结构,即可安全、高效地实现键名净化,兼顾开发效率与数据完整性。











