新增方法解析为 {{key}} 格式的 json
This commit is contained in:
parent
03ab867c4f
commit
175fbf93a2
@ -1,8 +1,14 @@
|
||||
package com.example.demo.draft.demo043.util;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@ -72,6 +78,7 @@ import java.util.regex.Pattern;
|
||||
* <p><b>创建时间:</b> 2024年</p>
|
||||
* <p><b>维护者:</b> demo043项目组</p>
|
||||
*/
|
||||
@Slf4j
|
||||
public class FormatUtil {
|
||||
|
||||
/**
|
||||
@ -1371,17 +1378,234 @@ public class FormatUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 偷梁换柱 - 支持正则表达式和多种替换选项
|
||||
* @param source 源字符串
|
||||
* @param replacementMap 替换映射关系
|
||||
* @return 替换后的字符串
|
||||
* 字符串批量替换工具方法
|
||||
*
|
||||
* <p>该方法提供强大的字符串替换功能,支持正则表达式和普通字符串替换,
|
||||
* 可灵活控制大小写敏感和整词匹配等选项。方法名"偷梁换柱"形象地描述了替换功能。</p>
|
||||
*
|
||||
* <p>功能特性:</p>
|
||||
* <ul>
|
||||
* <li>支持正则表达式替换和普通字符串替换</li>
|
||||
* <li>可配置大小写敏感匹配</li>
|
||||
* <li>支持整词匹配(word boundary)</li>
|
||||
* <li>提供正则表达式错误降级处理</li>
|
||||
* <li>支持批量替换操作</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param source 源字符串,如果为null则直接返回null
|
||||
* @param replacementMap 替换映射表,Key为要查找的模式(正则表达式或普通字符串),
|
||||
* Value为替换内容。如果为null或空则返回原字符串
|
||||
* @param caseSensitive 是否大小写敏感
|
||||
* true: 区分大小写,false: 不区分大小写
|
||||
* @param wholeWord 是否整词匹配
|
||||
* true: 只匹配完整单词,false: 匹配任意位置
|
||||
* @param useRegex 是否使用正则表达式
|
||||
* true: 将key作为正则表达式处理,false: 作为普通字符串处理
|
||||
* @return 替换后的字符串,如果源字符串或替换映射表为null/空则返回原字符串
|
||||
* @throws IllegalArgumentException 当replacementMap包含null键或值时抛出
|
||||
*/
|
||||
public static String stealBeamsAndReplacePillars(String source, Map<String, String> replacementMap) {
|
||||
return stealBeamsAndReplacePillars(source, replacementMap, false, false);
|
||||
public static String stealBeamsAndReplacePillars(String source, Map<String, String> replacementMap,
|
||||
boolean caseSensitive, boolean wholeWord, boolean useRegex) {
|
||||
// 参数校验:如果源字符串或替换映射表为空,直接返回原字符串
|
||||
if (source == null || source.isEmpty()) {
|
||||
log.debug("源字符串为空,直接返回");
|
||||
return source;
|
||||
}
|
||||
|
||||
if (replacementMap == null || replacementMap.isEmpty()) {
|
||||
log.debug("替换映射表为空,直接返回原字符串");
|
||||
return source;
|
||||
}
|
||||
|
||||
// 检查替换映射表中是否包含null键或值
|
||||
for (Map.Entry<String, String> entry : replacementMap.entrySet()) {
|
||||
if (entry.getKey() == null) {
|
||||
throw new IllegalArgumentException("替换映射表中不能包含null键");
|
||||
}
|
||||
if (entry.getValue() == null) {
|
||||
log.warn("替换映射表中键 '{}' 的值为null,将作为空字符串处理", entry.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
log.info("开始字符串替换处理,源字符串长度: {}, 替换规则数量: {}, 大小写敏感: {}, 整词匹配: {}, 使用正则: {}",
|
||||
source.length(), replacementMap.size(), match(caseSensitive), match(wholeWord), match(useRegex));
|
||||
|
||||
String result = source;
|
||||
int totalReplacements = 0;
|
||||
|
||||
// 遍历替换映射表,按顺序应用每个替换规则
|
||||
for (Map.Entry<String, String> entry : replacementMap.entrySet()) {
|
||||
String patternStr = entry.getKey();
|
||||
String replacement = entry.getValue() != null ? entry.getValue() : "";
|
||||
|
||||
try {
|
||||
if (useRegex) {
|
||||
// 使用正则表达式替换
|
||||
log.info("应用替换规则(正则表达式替换): '{}' -> '{}'", patternStr, replacement);
|
||||
result = applyRegexReplacement(result, patternStr, replacement, caseSensitive, wholeWord);
|
||||
} else {
|
||||
// 使用普通字符串替换
|
||||
log.info("应用替换规则(普通字符串替换): '{}' -> '{}'", patternStr, replacement);
|
||||
result = applyLiteralReplacement(result, patternStr, replacement, caseSensitive, wholeWord);
|
||||
}
|
||||
|
||||
// 统计替换次数(通过比较字符串长度变化估算)
|
||||
if (!result.equals(source)) {
|
||||
totalReplacements++;
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("替换规则处理失败 - 模式: '{}', 替换值: '{}', 错误: {}",
|
||||
patternStr, replacement, e.getMessage());
|
||||
// 发生错误时继续处理下一个规则,不中断整个流程
|
||||
}
|
||||
}
|
||||
|
||||
log.info("字符串替换完成,总应用规则数: {}, 实际产生变化的规则数: {}",
|
||||
replacementMap.size(), totalReplacements);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 偷梁换柱 - 支持正则表达式和多种替换选项
|
||||
* 应用正则表达式替换
|
||||
*
|
||||
* @param source 源字符串
|
||||
* @param regex 正则表达式模式
|
||||
* @param replacement 替换内容
|
||||
* @param caseSensitive 是否大小写敏感
|
||||
* @param wholeWord 是否整词匹配
|
||||
* @return 替换后的字符串
|
||||
*/
|
||||
private static String applyRegexReplacement(String source, String regex, String replacement,
|
||||
boolean caseSensitive, boolean wholeWord) {
|
||||
String processedRegex = regex;
|
||||
|
||||
// 处理整词匹配:如果启用整词匹配且正则表达式尚未包含单词边界
|
||||
if (wholeWord && !processedRegex.startsWith("\\b") && !processedRegex.contains("\\b")) {
|
||||
processedRegex = "\\b" + processedRegex + "\\b";
|
||||
log.info("添加单词边界,处理后的正则: {}", processedRegex); // trace
|
||||
}
|
||||
|
||||
try {
|
||||
// 设置正则表达式标志
|
||||
int flags = caseSensitive ? 0 : Pattern.CASE_INSENSITIVE;
|
||||
Pattern pattern = Pattern.compile(processedRegex, flags);
|
||||
Matcher matcher = pattern.matcher(source);
|
||||
|
||||
String result = matcher.replaceAll(replacement);
|
||||
|
||||
// 记录替换详情(调试级别)
|
||||
if (log.isTraceEnabled() && !result.equals(source)) {
|
||||
int count = 0;
|
||||
matcher.reset();
|
||||
while (matcher.find()) count++;
|
||||
log.info("正则替换完成: '{}' 匹配 {} 次", regex, count); // trace
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.warn("正则表达式编译或执行失败,降级为普通字符串替换 - 模式: '{}', 错误: {}",
|
||||
regex, e.getMessage());
|
||||
// 降级处理:使用普通字符串替换
|
||||
return applyLiteralReplacement(source, regex, replacement, caseSensitive, wholeWord);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用普通字符串替换
|
||||
*
|
||||
* @param source 源字符串
|
||||
* @param literal 要查找的字符串
|
||||
* @param replacement 替换内容
|
||||
* @param caseSensitive 是否大小写敏感
|
||||
* @param wholeWord 是否整词匹配
|
||||
* @return 替换后的字符串
|
||||
*/
|
||||
private static String applyLiteralReplacement(String source, String literal, String replacement,
|
||||
boolean caseSensitive, boolean wholeWord) {
|
||||
if (wholeWord) {
|
||||
// 整词匹配处理:使用正则表达式实现单词边界匹配
|
||||
try {
|
||||
String regex = "\\b" + Pattern.quote(literal) + "\\b";
|
||||
int flags = caseSensitive ? 0 : Pattern.CASE_INSENSITIVE;
|
||||
Pattern pattern = Pattern.compile(regex, flags);
|
||||
return pattern.matcher(source).replaceAll(replacement);
|
||||
} catch (Exception e) {
|
||||
log.warn("整词匹配处理失败,使用普通替换 - 模式: '{}'", literal);
|
||||
// 降级为普通替换
|
||||
}
|
||||
}
|
||||
|
||||
// 普通字符串替换
|
||||
if (caseSensitive) {
|
||||
// 大小写敏感替换
|
||||
return source.replace(literal, replacement);
|
||||
} else {
|
||||
// 大小写不敏感替换(需要手动实现)
|
||||
return replaceIgnoreCase(source, literal, replacement);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 不区分大小写的字符串替换
|
||||
*
|
||||
* @param source 源字符串
|
||||
* @param target 要查找的字符串
|
||||
* @param replacement 替换内容
|
||||
* @return 替换后的字符串
|
||||
*/
|
||||
private static String replaceIgnoreCase(String source, String target, String replacement) {
|
||||
if (source == null || target == null || replacement == null) {
|
||||
return source;
|
||||
}
|
||||
|
||||
StringBuilder result = new StringBuilder();
|
||||
String lowerSource = source.toLowerCase();
|
||||
String lowerTarget = target.toLowerCase();
|
||||
int index = 0;
|
||||
int targetLength = target.length();
|
||||
int count = 0;
|
||||
|
||||
while (true) {
|
||||
int pos = lowerSource.indexOf(lowerTarget, index);
|
||||
if (pos == -1) break;
|
||||
|
||||
// 添加不匹配部分
|
||||
result.append(source, index, pos);
|
||||
// 添加替换内容
|
||||
result.append(replacement);
|
||||
|
||||
index = pos + targetLength;
|
||||
count++;
|
||||
}
|
||||
|
||||
// 添加剩余部分
|
||||
result.append(source.substring(index));
|
||||
|
||||
if (count > 0) {
|
||||
log.info("不区分大小写替换完成: '{}' 匹配 {} 次", target, count); // trace
|
||||
}
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 偷梁换柱 - 使用默认参数(使用正则)
|
||||
* @param source 源字符串
|
||||
* @param replacementMap 替换映射关系
|
||||
* @param caseSensitive 是否区分大小写
|
||||
* @param wholeWord 是否整词匹配
|
||||
* @return 替换后的字符串
|
||||
*/
|
||||
public static String stealBeamsAndReplacePillars(String source, Map<String, String> replacementMap,
|
||||
boolean caseSensitive, boolean wholeWord) {
|
||||
return stealBeamsAndReplacePillars(source, replacementMap, caseSensitive, wholeWord, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 偷梁换柱 - 使用默认参数(非整词匹配、使用正则)
|
||||
* @param source 源字符串
|
||||
* @param replacementMap 替换映射关系
|
||||
* @param caseSensitive 是否区分大小写
|
||||
@ -1392,41 +1616,184 @@ public class FormatUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 偷梁换柱
|
||||
* 偷梁换柱 - 使用默认参数(大小写不敏感、非整词匹配、使用正则)
|
||||
*
|
||||
* @param source 源字符串
|
||||
* @param replacementMap 替换映射关系
|
||||
* @param caseSensitive 是否区分大小写
|
||||
* @param wholeWord 是否整词匹配
|
||||
* @return 替换后的字符串
|
||||
*/
|
||||
public static String stealBeamsAndReplacePillars(String source, Map<String, String> replacementMap,
|
||||
boolean caseSensitive, boolean wholeWord) {
|
||||
if (source == null || replacementMap == null || replacementMap.isEmpty()) {
|
||||
return source;
|
||||
public static String stealBeamsAndReplacePillars(String source, Map<String, String> replacementMap) {
|
||||
return stealBeamsAndReplacePillars(source, replacementMap, false, false, true);
|
||||
}
|
||||
|
||||
String result = source;
|
||||
// ========== JSON对象再次加工 ==========
|
||||
|
||||
for (Map.Entry<String, String> entry : replacementMap.entrySet()) {
|
||||
String regex = entry.getKey();
|
||||
String replacement = entry.getValue();
|
||||
|
||||
// 处理整词匹配
|
||||
if (wholeWord && !regex.startsWith("\\b")) {
|
||||
regex = "\\b" + regex + "\\b";
|
||||
/**
|
||||
* 加载并预处理JSON文件
|
||||
*
|
||||
* <p>该方法读取JSON文件内容,解析为对象列表,并对所有键名进行标准化处理,
|
||||
* 将键名转换为双花括号格式({{key}})。主要用于模板处理或数据转换场景。</p>
|
||||
*
|
||||
* <p>处理流程:</p>
|
||||
* <ol>
|
||||
* <li>读取JSON文件内容为字符串</li>
|
||||
* <li>使用FastJSON库解析为对象列表</li>
|
||||
* <li>递归处理所有对象的键名,转换为{{key}}格式</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param processJSONFile JSON文件路径,不能为null或空字符串
|
||||
* @return 包含预处理后对象的列表,列表中的每个对象的所有键名都已转换为{{key}}格式
|
||||
* @throws IOException 当文件读取失败、文件不存在或文件格式错误时抛出
|
||||
* @throws IllegalArgumentException 当processJSONFile为null或空字符串时抛出
|
||||
*/
|
||||
public static List<Object> loadJSON(String processJSONFile) throws IOException {
|
||||
// 参数校验
|
||||
if (processJSONFile == null || processJSONFile.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("JSON文件路径不能为空或null");
|
||||
}
|
||||
|
||||
log.info("开始加载JSON文件: {}", processJSONFile);
|
||||
|
||||
try {
|
||||
int flags = caseSensitive ? 0 : Pattern.CASE_INSENSITIVE;
|
||||
Pattern pattern = Pattern.compile(regex, flags);
|
||||
Matcher matcher = pattern.matcher(result);
|
||||
result = matcher.replaceAll(replacement);
|
||||
// Step 1: 读取JSON文件内容
|
||||
log.debug("读取文件内容...");
|
||||
String targetContent = Files.readString(Path.of(processJSONFile), StandardCharsets.UTF_8);
|
||||
|
||||
if (targetContent == null || targetContent.trim().isEmpty()) {
|
||||
log.warn("JSON文件内容为空: {}", processJSONFile);
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
log.debug("文件内容读取成功,长度: {} 字符", targetContent.length());
|
||||
|
||||
// Step 2: 解析JSON字符串为对象列表
|
||||
log.debug("解析JSON内容...");
|
||||
List<Object> list = JSON.parseArray(targetContent);
|
||||
|
||||
if (list == null) {
|
||||
log.warn("JSON解析结果为null,返回空列表");
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
log.debug("JSON解析成功,对象数量: {}", list.size());
|
||||
|
||||
// Step 3: 处理所有对象的键名,转换为{{key}}格式
|
||||
log.debug("开始处理键名格式转换...");
|
||||
List<Object> processedList = processKeysToMustacheFormat(list);
|
||||
|
||||
log.info("JSON文件加载完成,共处理 {} 个对象", processedList.size());
|
||||
return processedList;
|
||||
|
||||
} catch (IOException e) {
|
||||
log.error("读取JSON文件失败: {}", processJSONFile, e);
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
System.err.println("正则表达式错误: " + regex + " - " + e.getMessage());
|
||||
log.error("解析JSON内容失败: {}", processJSONFile, e);
|
||||
throw new IOException("JSON解析失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
/**
|
||||
* 递归处理对象中的所有键名,转换为双花括号格式
|
||||
*
|
||||
* <p>该方法会遍历对象的所有层级,将每个键名从"key"格式转换为"{{key}}"格式</p>
|
||||
*
|
||||
* @param originalList 原始对象列表
|
||||
* @return 键名转换后的新对象列表
|
||||
*/
|
||||
private static List<Object> processKeysToMustacheFormat(List<Object> originalList) {
|
||||
if (originalList == null || originalList.isEmpty()) {
|
||||
return originalList;
|
||||
}
|
||||
|
||||
List<Object> processedList = new ArrayList<>(originalList.size());
|
||||
|
||||
for (int i = 0; i < originalList.size(); i++) {
|
||||
try {
|
||||
Object item = originalList.get(i);
|
||||
Object processedItem = processSingleObject(item);
|
||||
processedList.add(processedItem);
|
||||
|
||||
if (log.isDebugEnabled() && i % 100 == 0) {
|
||||
log.debug("已处理 {} 个对象", i);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("处理第 {} 个对象时发生异常,跳过该对象", i, e);
|
||||
// 发生异常时保留原始对象
|
||||
processedList.add(originalList.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
return processedList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理单个对象的键名转换
|
||||
*
|
||||
* @param obj 要处理的对象,支持Map、List和基本类型
|
||||
* @return 键名转换后的新对象
|
||||
*/
|
||||
private static Object processSingleObject(Object obj) {
|
||||
if (obj instanceof Map) {
|
||||
// 处理Map对象
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> originalMap = (Map<String, Object>) obj;
|
||||
Map<String, Object> processedMap = new HashMap<>(originalMap.size());
|
||||
|
||||
for (Map.Entry<String, Object> entry : originalMap.entrySet()) {
|
||||
String originalKey = entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
|
||||
// 转换键名格式:key -> {{key}}
|
||||
String processedKey = convertKeyToMustacheFormat(originalKey);
|
||||
// 递归处理值
|
||||
Object processedValue = processSingleObject(value);
|
||||
|
||||
processedMap.put(processedKey, processedValue);
|
||||
}
|
||||
return processedMap;
|
||||
|
||||
} else if (obj instanceof List) {
|
||||
// 处理List对象
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Object> originalList = (List<Object>) obj;
|
||||
List<Object> processedList = new ArrayList<>(originalList.size());
|
||||
|
||||
for (Object item : originalList) {
|
||||
processedList.add(processSingleObject(item));
|
||||
}
|
||||
return processedList;
|
||||
|
||||
} else {
|
||||
// 基本类型(String、Number、Boolean等)直接返回
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将键名转换为双花括号格式
|
||||
*
|
||||
* <p>如果键名已经包含花括号,则不再重复添加</p>
|
||||
*
|
||||
* @param key 原始键名
|
||||
* @return 转换后的键名,格式为{{key}}
|
||||
*/
|
||||
private static String convertKeyToMustacheFormat(String key) {
|
||||
if (key == null || key.trim().isEmpty()) {
|
||||
log.warn("遇到空键名,返回原始值");
|
||||
return key;
|
||||
}
|
||||
|
||||
// 如果键名已经是{{key}}格式,则不再处理
|
||||
if (key.startsWith("{{") && key.endsWith("}}")) {
|
||||
return key;
|
||||
}
|
||||
|
||||
// 转换为{{key}}格式
|
||||
return "{{" + key + "}}";
|
||||
}
|
||||
|
||||
private static String match(boolean flag) {
|
||||
return flag ? "启用" : "禁用";
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user