From 445e3e2ad5547e4acbeab70249b33cc27028379b Mon Sep 17 00:00:00 2001 From: yuejiajun <1530620364@qq.com> Date: Sun, 28 Sep 2025 13:16:25 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=9F=E8=AE=A1=E8=A7=84=E5=88=99=E7=94=9F?= =?UTF-8?q?=E6=95=88=E4=B8=8E=E6=9C=AA=E7=94=9F=E6=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../demo/draft/demo043/util/FormatUtil.java | 221 +++++++++++++++++- 1 file changed, 210 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/example/demo/draft/demo043/util/FormatUtil.java b/src/main/java/com/example/demo/draft/demo043/util/FormatUtil.java index 186bdb3..cc8b2a6 100644 --- a/src/main/java/com/example/demo/draft/demo043/util/FormatUtil.java +++ b/src/main/java/com/example/demo/draft/demo043/util/FormatUtil.java @@ -7,6 +7,8 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.text.SimpleDateFormat; import java.util.*; import java.util.regex.Matcher; @@ -1388,8 +1390,8 @@ public class FormatUtil { *
  • 支持正则表达式替换和普通字符串替换
  • *
  • 可配置大小写敏感匹配
  • *
  • 支持整词匹配(word boundary)
  • - *
  • 提供正则表达式错误降级处理
  • - *
  • 支持批量替换操作
  • + *
  • 提供详细的替换统计信息
  • + *
  • 记录未生效的替换规则
  • * * * @param source 源字符串,如果为null则直接返回null @@ -1402,7 +1404,7 @@ public class FormatUtil { * @param useRegex 是否使用正则表达式 * true: 将key作为正则表达式处理,false: 作为普通字符串处理 * @return 替换后的字符串,如果源字符串或替换映射表为null/空则返回原字符串 - * @throws IllegalArgumentException 当replacementMap包含null键或值时抛出 + * @throws IllegalArgumentException 当replacementMap包含null键时抛出 */ public static String stealBeamsAndReplacePillars(String source, Map replacementMap, boolean caseSensitive, boolean wholeWord, boolean useRegex) { @@ -1432,41 +1434,238 @@ public class FormatUtil { String result = source; int totalReplacements = 0; + List ineffectiveRules = new ArrayList<>(); // 记录未生效的规则 + Map replacementStats = new HashMap<>(); // 记录每个规则的替换次数 + + // 计算源字符串的SHA1,用于精确比较变化 + String sourceHash = calculateSHA1(source); + String currentResult = source; + String currentHash = sourceHash; // 遍历替换映射表,按顺序应用每个替换规则 for (Map.Entry entry : replacementMap.entrySet()) { String patternStr = entry.getKey(); String replacement = entry.getValue() != null ? entry.getValue() : ""; + String previousHash = currentHash; // 记录应用规则前的hash + try { if (useRegex) { // 使用正则表达式替换 - log.info("应用替换规则(正则表达式替换): '{}' -> '{}'", patternStr, replacement); - result = applyRegexReplacement(result, patternStr, replacement, caseSensitive, wholeWord); + log.debug("应用替换规则(正则表达式替换): '{}' -> '{}'", patternStr, replacement); + result = applyRegexReplacement(result, patternStr, replacement, caseSensitive, wholeWord, replacementStats); } else { // 使用普通字符串替换 - log.info("应用替换规则(普通字符串替换): '{}' -> '{}'", patternStr, replacement); - result = applyLiteralReplacement(result, patternStr, replacement, caseSensitive, wholeWord); + log.debug("应用替换规则(普通字符串替换): '{}' -> '{}'", patternStr, replacement); + result = applyLiteralReplacement(result, patternStr, replacement, caseSensitive, wholeWord, replacementStats); } - // 统计替换次数(通过比较字符串长度变化估算) - if (!result.equals(source)) { + // 计算当前结果的hash值 + currentResult = result; + currentHash = calculateSHA1(currentResult); + + // 统计替换次数:通过SHA1比较判断是否发生变化 + boolean hasChanged = !currentHash.equals(previousHash); + int ruleReplacementCount = replacementStats.getOrDefault(patternStr, 0); + + if (hasChanged && ruleReplacementCount > 0) { totalReplacements++; + log.info("规则 '{}' 生效,替换次数: {}", patternStr, ruleReplacementCount); + } else { + // 记录未生效的规则 + ineffectiveRules.add(patternStr); + log.info("规则 '{}' 未生效,未找到匹配项", patternStr); } } catch (Exception e) { log.error("替换规则处理失败 - 模式: '{}', 替换值: '{}', 错误: {}", patternStr, replacement, e.getMessage()); + // 发生错误时,该规则视为未生效 + ineffectiveRules.add(patternStr); // 发生错误时继续处理下一个规则,不中断整个流程 } } - log.info("字符串替换完成,总应用规则数: {}, 实际产生变化的规则数: {}", - replacementMap.size(), totalReplacements); + // 输出详细的统计信息 + log.info("字符串替换完成,总应用规则数: {}, 实际产生变化的规则数: {}, 总替换次数: {}", + replacementMap.size(), totalReplacements, calculateTotalReplacements(replacementStats)); + + // 输出未生效的规则(DEBUG级别) + if (!ineffectiveRules.isEmpty() && log.isDebugEnabled()) { + log.info("以下 {} 个规则未生效: {}", ineffectiveRules.size(), ineffectiveRules); + } + + // 输出每个规则的详细替换统计(DEBUG级别) + if (log.isDebugEnabled()) { + log.info("详细替换统计:"); + for (Map.Entry stat : replacementStats.entrySet()) { + String rule = stat.getKey(); + int count = stat.getValue(); + String status = count > 0 ? "生效" : "未生效"; + log.info("规则 '{}': {}次替换 - {}", rule, count, status); + } + } return result; } + /** + * 计算字符串的SHA1哈希值 + * + * @param input 输入字符串 + * @return SHA1哈希值,如果输入为null则返回空字符串 + */ + private static String calculateSHA1(String input) { + if (input == null) { + return ""; + } + try { + MessageDigest digest = MessageDigest.getInstance("SHA-1"); + byte[] hash = digest.digest(input.getBytes(StandardCharsets.UTF_8)); + StringBuilder hexString = new StringBuilder(); + for (byte b : hash) { + String hex = Integer.toHexString(0xff & b); + if (hex.length() == 1) hexString.append('0'); + hexString.append(hex); + } + return hexString.toString(); + } catch (NoSuchAlgorithmException e) { + log.warn("SHA1算法不可用,使用简单hash替代", e); + // 降级方案:使用简单的hashCode + return Integer.toHexString(input.hashCode()); + } + } + + /** + * 应用正则表达式替换,并统计替换次数 + */ + private static String applyRegexReplacement(String source, String regex, String replacement, + boolean caseSensitive, boolean wholeWord, + Map stats) { + String processedRegex = regex; + + // 处理整词匹配 + if (wholeWord && !processedRegex.startsWith("\\b") && !processedRegex.contains("\\b")) { + processedRegex = "\\b" + processedRegex + "\\b"; + log.trace("添加单词边界,处理后的正则: {}", processedRegex); + } + + try { + int flags = caseSensitive ? 0 : Pattern.CASE_INSENSITIVE; + Pattern pattern = Pattern.compile(processedRegex, flags); + Matcher matcher = pattern.matcher(source); + + // 先统计匹配次数 + int count = 0; + while (matcher.find()) { + count++; + } + + // 记录统计信息 + stats.put(regex, count); + + // 执行替换 + if (count > 0) { + matcher.reset(); + return matcher.replaceAll(replacement); + } else { + return source; // 无匹配,返回原字符串 + } + + } catch (Exception e) { + log.warn("正则表达式编译或执行失败,降级为普通字符串替换 - 模式: '{}', 错误: {}", + regex, e.getMessage()); + // 降级处理:使用普通字符串替换 + return applyLiteralReplacement(source, regex, replacement, caseSensitive, wholeWord, stats); + } + } + + /** + * 应用普通字符串替换,并统计替换次数 + */ + private static String applyLiteralReplacement(String source, String literal, String replacement, + boolean caseSensitive, boolean wholeWord, + Map stats) { + if (wholeWord) { + // 整词匹配处理:使用正则表达式实现单词边界匹配 + try { + String regex = "\\b" + Pattern.quote(literal) + "\\b"; + int flags = caseSensitive ? 0 : Pattern.CASE_INSENSITIVE; + Pattern pattern = Pattern.compile(regex, flags); + Matcher matcher = pattern.matcher(source); + + // 统计匹配次数 + int count = 0; + while (matcher.find()) { + count++; + } + + // 记录统计信息 + stats.put(literal, count); + + // 执行替换 + if (count > 0) { + matcher.reset(); + return matcher.replaceAll(replacement); + } else { + return source; // 无匹配,返回原字符串 + } + } catch (Exception e) { + log.warn("整词匹配处理失败,使用普通替换 - 模式: '{}'", literal); + // 降级为普通替换 + } + } + + // 普通字符串替换 + int count; + String result; + + if (caseSensitive) { + // 大小写敏感替换 + result = source.replace(literal, replacement); + // 计算替换次数(通过字符串分割方式) + count = (source.length() - result.length()) / (literal.length() - replacement.length()); + if (count < 0) count = 0; // 处理除数为0的情况 + } else { + // 大小写不敏感替换 + result = replaceIgnoreCase(source, literal, replacement); + count = countIgnoreCaseOccurrences(source, literal); + } + + // 记录统计信息 + stats.put(literal, count); + + return result; + } + + /** + * 计算字符串中不区分大小写的出现次数 + */ + private static int countIgnoreCaseOccurrences(String source, String target) { + if (source == null || target == null || target.isEmpty()) { + return 0; + } + + int count = 0; + String lowerSource = source.toLowerCase(); + String lowerTarget = target.toLowerCase(); + int index = 0; + + while ((index = lowerSource.indexOf(lowerTarget, index)) != -1) { + count++; + index += target.length(); + } + + return count; + } + + /** + * 计算总替换次数 + */ + private static int calculateTotalReplacements(Map stats) { + return stats.values().stream().mapToInt(Integer::intValue).sum(); + } + /** * 应用正则表达式替换 *