统计规则生效与未生效
This commit is contained in:
parent
175fbf93a2
commit
445e3e2ad5
@ -7,6 +7,8 @@ import java.io.IOException;
|
|||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
@ -1388,8 +1390,8 @@ public class FormatUtil {
|
|||||||
* <li>支持正则表达式替换和普通字符串替换</li>
|
* <li>支持正则表达式替换和普通字符串替换</li>
|
||||||
* <li>可配置大小写敏感匹配</li>
|
* <li>可配置大小写敏感匹配</li>
|
||||||
* <li>支持整词匹配(word boundary)</li>
|
* <li>支持整词匹配(word boundary)</li>
|
||||||
* <li>提供正则表达式错误降级处理</li>
|
* <li>提供详细的替换统计信息</li>
|
||||||
* <li>支持批量替换操作</li>
|
* <li>记录未生效的替换规则</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @param source 源字符串,如果为null则直接返回null
|
* @param source 源字符串,如果为null则直接返回null
|
||||||
@ -1402,7 +1404,7 @@ public class FormatUtil {
|
|||||||
* @param useRegex 是否使用正则表达式
|
* @param useRegex 是否使用正则表达式
|
||||||
* true: 将key作为正则表达式处理,false: 作为普通字符串处理
|
* true: 将key作为正则表达式处理,false: 作为普通字符串处理
|
||||||
* @return 替换后的字符串,如果源字符串或替换映射表为null/空则返回原字符串
|
* @return 替换后的字符串,如果源字符串或替换映射表为null/空则返回原字符串
|
||||||
* @throws IllegalArgumentException 当replacementMap包含null键或值时抛出
|
* @throws IllegalArgumentException 当replacementMap包含null键时抛出
|
||||||
*/
|
*/
|
||||||
public static String stealBeamsAndReplacePillars(String source, Map<String, String> replacementMap,
|
public static String stealBeamsAndReplacePillars(String source, Map<String, String> replacementMap,
|
||||||
boolean caseSensitive, boolean wholeWord, boolean useRegex) {
|
boolean caseSensitive, boolean wholeWord, boolean useRegex) {
|
||||||
@ -1432,41 +1434,238 @@ public class FormatUtil {
|
|||||||
|
|
||||||
String result = source;
|
String result = source;
|
||||||
int totalReplacements = 0;
|
int totalReplacements = 0;
|
||||||
|
List<String> ineffectiveRules = new ArrayList<>(); // 记录未生效的规则
|
||||||
|
Map<String, Integer> replacementStats = new HashMap<>(); // 记录每个规则的替换次数
|
||||||
|
|
||||||
|
// 计算源字符串的SHA1,用于精确比较变化
|
||||||
|
String sourceHash = calculateSHA1(source);
|
||||||
|
String currentResult = source;
|
||||||
|
String currentHash = sourceHash;
|
||||||
|
|
||||||
// 遍历替换映射表,按顺序应用每个替换规则
|
// 遍历替换映射表,按顺序应用每个替换规则
|
||||||
for (Map.Entry<String, String> entry : replacementMap.entrySet()) {
|
for (Map.Entry<String, String> entry : replacementMap.entrySet()) {
|
||||||
String patternStr = entry.getKey();
|
String patternStr = entry.getKey();
|
||||||
String replacement = entry.getValue() != null ? entry.getValue() : "";
|
String replacement = entry.getValue() != null ? entry.getValue() : "";
|
||||||
|
|
||||||
|
String previousHash = currentHash; // 记录应用规则前的hash
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (useRegex) {
|
if (useRegex) {
|
||||||
// 使用正则表达式替换
|
// 使用正则表达式替换
|
||||||
log.info("应用替换规则(正则表达式替换): '{}' -> '{}'", patternStr, replacement);
|
log.debug("应用替换规则(正则表达式替换): '{}' -> '{}'", patternStr, replacement);
|
||||||
result = applyRegexReplacement(result, patternStr, replacement, caseSensitive, wholeWord);
|
result = applyRegexReplacement(result, patternStr, replacement, caseSensitive, wholeWord, replacementStats);
|
||||||
} else {
|
} else {
|
||||||
// 使用普通字符串替换
|
// 使用普通字符串替换
|
||||||
log.info("应用替换规则(普通字符串替换): '{}' -> '{}'", patternStr, replacement);
|
log.debug("应用替换规则(普通字符串替换): '{}' -> '{}'", patternStr, replacement);
|
||||||
result = applyLiteralReplacement(result, patternStr, replacement, caseSensitive, wholeWord);
|
result = applyLiteralReplacement(result, patternStr, replacement, caseSensitive, wholeWord, replacementStats);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 统计替换次数(通过比较字符串长度变化估算)
|
// 计算当前结果的hash值
|
||||||
if (!result.equals(source)) {
|
currentResult = result;
|
||||||
|
currentHash = calculateSHA1(currentResult);
|
||||||
|
|
||||||
|
// 统计替换次数:通过SHA1比较判断是否发生变化
|
||||||
|
boolean hasChanged = !currentHash.equals(previousHash);
|
||||||
|
int ruleReplacementCount = replacementStats.getOrDefault(patternStr, 0);
|
||||||
|
|
||||||
|
if (hasChanged && ruleReplacementCount > 0) {
|
||||||
totalReplacements++;
|
totalReplacements++;
|
||||||
|
log.info("规则 '{}' 生效,替换次数: {}", patternStr, ruleReplacementCount);
|
||||||
|
} else {
|
||||||
|
// 记录未生效的规则
|
||||||
|
ineffectiveRules.add(patternStr);
|
||||||
|
log.info("规则 '{}' 未生效,未找到匹配项", patternStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("替换规则处理失败 - 模式: '{}', 替换值: '{}', 错误: {}",
|
log.error("替换规则处理失败 - 模式: '{}', 替换值: '{}', 错误: {}",
|
||||||
patternStr, replacement, e.getMessage());
|
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<String, Integer> stat : replacementStats.entrySet()) {
|
||||||
|
String rule = stat.getKey();
|
||||||
|
int count = stat.getValue();
|
||||||
|
String status = count > 0 ? "生效" : "未生效";
|
||||||
|
log.info("规则 '{}': {}次替换 - {}", rule, count, status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
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<String, Integer> 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<String, Integer> 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<String, Integer> stats) {
|
||||||
|
return stats.values().stream().mapToInt(Integer::intValue).sum();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 应用正则表达式替换
|
* 应用正则表达式替换
|
||||||
*
|
*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user