package cn.iocoder.yudao.module.llm.utils;

import com.github.houbb.opencc4j.util.ZhConverterUtil;
import com.github.houbb.sensitive.word.core.SensitiveWordHelper;
import lombok.extern.slf4j.Slf4j;

import java.nio.charset.StandardCharsets;
import java.time.Year;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Slf4j
public class DataProcessUtil {

    /*
     * ---------------------------------------------------------------
     *              🔖 【 异常清洗配置 】
     * ---------------------------------------------------------------
     */

    /**
     * 移除不可见字
     * 移除ASCII中的一些不可见字符, 如0-32 和127-160这两个范围
     *
     * @param input
     * @return
     */
    public static String removeNonVisibleAsciiChars (String input) {
        // 使用StringBuilder来构建正则表达式，因为我们需要动态地添加字符范围
        StringBuilder regex = new StringBuilder();
        regex.append("[\\x00-\\x1F]"); // 0-31范围的字符
        regex.append("|");            // OR 操作符
        regex.append("[\\x7F-\\xA0]"); // 127-160范围的字符

        // 使用replaceAll方法和构建的正则表达式来移除不可见字符
        return input.replaceAll(regex.toString(), "");
    }

    /**
     * 移除不可见字符
     * <p>
     * 将不同的unicode空格比如  u2008，转成正常的空格
     *
     * @param input
     * @return
     */
    public static String convertUnicodeSpacesToNormalSpaces (String input) {
        // Unicode空格字符的正则表达式，包括但不限于u2008等
        String unicodeSpacesRegex = "[\\u0020\\u00A0\\u1680\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000]";

        // 使用正则表达式替换匹配的Unicode空格字符为普通空格
        return input.replaceAll(unicodeSpacesRegex, " ");
    }

    /**
     * 移除不可见字符
     * <p>
     * 去除乱码和无意义的unicode
     *
     * @param input
     * @return
     */
    public static String removeNonPrintableUnicodeChars (String input) {
        // 构建一个正则表达式，匹配所有非打印ASCII和非打印Unicode字符
        // \p{C} 匹配所有控制字符和格式字符
        // \p{Zs} 匹配所有空白分隔符（比如U+2000到U+200F之间的字符）
        // 注意：有些空白字符可能是有意义的，比如空格（U+0020），所以这里的选择要谨慎
        // 如果你确定某些空白字符是无意义的，可以将其添加到正则表达式中
        String regex = "[\\p{C}\\p{Zs}&&[^\\s]]+|\\u0000"; // \\u0000 是NULL字符，通常是无意义的

        // 使用replaceAll方法移除匹配的字符
        // 注意：这里使用了两个替换步骤，因为直接替换可能会导致正则表达式匹配问题
        // 首先替换掉所有匹配的字符为一个占位符（比如"*"），然后再替换掉占位符为空字符串
        // 这样做是为了避免在替换过程中正则表达式匹配到已经被替换掉的部分
        // 但在这种情况下，由于我们使用的是字符类匹配，其实直接替换为空字符串也是可以的
        // 下面的代码为了演示这种可能的复杂性而保留了两步替换的逻辑
        String intermediate = input.replaceAll(regex, "*"); // 这一步其实是多余的，但为了说明而保留
        return intermediate.replaceAll("[*]+", ""); // 这一步实际上完成了去除非打印字符的任务

        // 简化版：直接替换为空字符串
        // return input.replaceAll(regex, "");
    }

    /**
     * 繁体转简体
     * <p>
     * 繁体转简体，如“不經意，妳的笑容”清洗成“不经意，你的笑容”
     *
     * @param input
     * @return
     */
    public static String traditionalToSimplified (String input) {
        return ZhConverterUtil.toSimple(input);
    }

    // 使用正则表达式匹配HTML标签
    private static final String HTML_TAG_REGEX = "<[^>]+>";

    /**
     * 去除网页标识符
     * <p>
     * 移除文档中的html标签，如<html>,<dev><p>等
     *
     * @param input
     * @return
     */
    public static String removeHtmlTags (String input) {
        if (input == null || input.isEmpty()) {
            return input;
        }
        // 使用replaceAll方法替换匹配的HTML标签为空字符串
        return input.replaceAll(HTML_TAG_REGEX, "");
    }

    // 这是一个简化的正则表达式，用于匹配常见的emoji表情符号。
    // 请注意，它可能不会涵盖所有可能的emoji，因为Unicode标准在不断发展。
    private static final String EMOJI_REGEX = "[\\uD83C-\\uD83D\\uD83E-\\uD83F\\u2600-\\u27FF"
                                              + "\\u2B00-\\u2BFF\\u2F00-\\u2FFF\\u3000-\\u303F"
                                              + "\\u3200-\\u32FF\\uA490-\\uA4CF\\uA900-\\uA97F"
                                              + "\\uAC00-\\uAC7F\\uAC80-\\uACFF\\uD700-\\uD7AF"
                                              + "\\uF900-\\uFAFF\\uFB00-\\uFB4F\\uFB50-\\uFDFF"
                                              + "\\uFE00-\\uFE6F\\uFE70-\\uFEFF\\uFF00-\\uFFEF]";

    /**
     * 去除表情
     * <p>
     * 去除文档中的表情，如‘🐰’、‘👵’等
     *
     * @param input
     * @return
     */
    public static String removeEmojis (String input) {
        if (input == null || input.isEmpty()) {
            return input;
        }
        Pattern pattern = Pattern.compile(EMOJI_REGEX, Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(input);
        return matcher.replaceAll("");
    }

    // 正则表达式用于匹配中文词汇（这里假设词汇由连续的中文字符组成）
    private static final String CHINESE_WORD_REGEX = "[\\u4e00-\\u9fff]+";

    // 方法：计算字符串中的中文字符数量
    // 注意：这里假设输入字符串只包含中文字符和可能的分隔符（如空格、标点符号等）
    // 并且中文字符在UTF-16编码中占用两个char，但被视为一个逻辑字符
    private static int countChineseChars (String input) {
        // 使用正则表达式匹配中文词汇，并计算匹配到的字符总数（这里需要除以2，因为每个中文字符占用两个char）
        // 但为了简化，我们可以直接遍历字符，检查每个字符是否在中文范围内
        int count = 0;
        for (char c : input.toCharArray()) {
            if (Character.UnicodeBlock.of(c) == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
                || Character.UnicodeBlock.of(c) == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
                || Character.UnicodeBlock.of(c) == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
                // 可以根据需要添加更多Unicode块
            ) {
                count++;
            }
        }
        return count;
    }

    /*
     * ---------------------------------------------------------------
     *              🔖 【 过滤配置 】
     * ---------------------------------------------------------------
     */

    /**
     * 检查文档的词数目
     * 词数目不在指定范围会被过滤掉，如中文[1,1000000]
     *
     * @param text
     * @param minChars
     * @param maxChars
     * @return
     */
    public static List<String> filterWords (String text, int minChars, int maxChars) {
        List<String> result = new ArrayList<>();
        Pattern pattern = Pattern.compile(CHINESE_WORD_REGEX);
        Matcher matcher = pattern.matcher(text);

        while (matcher.find()) {
            String word = matcher.group();
            int chineseCharCount = countChineseChars(word); // 计算中文字符数量
            if (chineseCharCount >= minChars && chineseCharCount <= maxChars) {
                result.add(word);
            }
        }
        return result;
    }

    /**
     * 检查文档的字重复率
     * <p>
     * 如果字重复率太高，意味着文档中重复的字太多，文档会被过滤掉
     * </p>
     *
     * @param content   文档行
     * @param threshold 设置字重复率的阈值，例如10%
     * @return true表示字重复率低于阈值，false表示字重复率高于阈值，文档会被过滤掉
     */
    public static boolean calculateCharacterRepetitionRate (String content, double threshold) {
        //        StringBuilder content = new StringBuilder();
        //        for (String line : lines) {
        //            content.append(line);
        //        }

        // 统计字符出现次数
        Map<Character, Integer> charCount = new HashMap<>();
        for (char c : content.toCharArray()) {
            charCount.put(c, charCount.getOrDefault(c, 0) + 1);
        }

        // 计算重复字符数和总字符数
        int totalChars = content.length();
        int repeatedChars = 0;
        for (int count : charCount.values()) {
            if (count > 1) {
                // 只计算重复的部分
                repeatedChars += count - 1;
            }
        }

        // 计算字重复率
        double repetitionRate = (double) repeatedChars / totalChars;

        // 打印重复率和阈值，方便调试
        log.info("字重复率: " + repetitionRate);
        log.info("阈值: " + threshold);

        // 如果重复率超过阈值，返回true表示需要过滤掉文档
        return repetitionRate > threshold;
    }

    // 简单的基于空格和标点符号的分词方法
    private static List<String> tokenize (String text) {
        // 使用正则表达式匹配非单词字符（包括空格、标点符号等），并将它们作为分隔符
        Pattern pattern = Pattern.compile("\\W+");
        String[] words = pattern.split(text.toLowerCase()); // 转换为小写以进行不区分大小写的比较
        List<String> tokens = new ArrayList<>();
        for (String word : words) {
            if (!word.isEmpty()) { // 排除空字符串
                tokens.add(word);
            }
        }
        return tokens;
    }

    // 方法：计算文档的词重复率

    /**
     * 检查文档的词重复率
     * <p>
     * 如果词重复率太高，意味着文档中重复的词太多，文档会被过滤掉
     *
     * @param content
     * @param threshold
     * @return
     */
    public static boolean calculateWordRepetitionRate (String content, double threshold) {
        // 分词
        List<String> words = tokenize(content);

        // 统计词出现次数
        Map<String, Integer> wordCount = new HashMap<>();
        for (String word : words) {
            wordCount.put(word, wordCount.getOrDefault(word, 0) + 1);
        }

        // 计算重复词数和总词数
        int totalWords = words.size();
        int repeatedWords = 0;
        for (int count : wordCount.values()) {
            if (count > 1) {
                repeatedWords += (count - 1); // 只计算重复的部分
            }
        }

        // 计算词重复率
        double repetitionRate = (double) repeatedWords / totalWords;

        // 打印重复率和阈值，方便调试
        log.info("词重复率: " + repetitionRate);
        log.info("阈值: " + threshold);

        // 如果重复率超过阈值，返回true表示需要过滤掉文档
        return repetitionRate > threshold;
    }

    /**
     * 检查文档的特殊字符率
     * 如果特殊字符率太高，意味着文档中特殊字符太多，文档会被过滤掉
     *
     * @param content
     * @param threshold
     * @return
     */
    public static boolean checkSpecialCharacterRate (String content, double threshold) {

        log.info("特殊字符检测：{}", content);
        // 使用正则表达式匹配特殊字符（非字母数字字符）
        Pattern pattern = Pattern.compile("[^a-zA-Z0-9]");
        Matcher matcher = pattern.matcher(content);

        // 统计特殊字符的数量
        int specialCharCount = 0;
        while (matcher.find()) {
            specialCharCount++;
        }

        // 计算文档的总字符数（不包括换行符等空白字符，可以根据需要调整）
        int totalCharCount = content.length(); // 或者使用 content.replaceAll("\\s+", "").length() 来排除空白字符

        // 计算特殊字符率
        double specialCharRate = (double) specialCharCount / totalCharCount;

        // 打印特殊字符率和阈值，方便调试
        log.info("特殊字符率: " + specialCharRate);
        log.info("阈值: " + threshold);

        // 如果特殊字符率超过阈值，返回true表示需要过滤掉文档
        return specialCharRate > threshold;
    }

    /**
     * 检查文档的色情暴力词率
     * <p>
     * 如果色情暴力词率太高，文档会被过滤掉，取值范围[0,100]。
     * </p>
     *
     * @param content   文本内容
     * @param threshold 阈值
     * @return 是否过滤文档
     */
    public static boolean checkSensitiveWordRate (String content, double threshold) {
        // TODO: 先使用 sensitive-word 处理，有修改再调整

        // 检测是否包含色情暴力词
        boolean isFalse = SensitiveWordHelper.contains(content);
        if (!isFalse) {
            return false;
        }

        //返回所有敏感词
        List<String> wordList = SensitiveWordHelper.findAll(content);
        log.info("返回所有敏感词====>>>>{}", wordList);

        // 统计敏感词的字符数量
        int sensitiveWordLength = 0;
        for (String word : wordList) {
            sensitiveWordLength += word.length();
        }
        // 计算文档的总字符数（不包括换行符等空白字符，可以根据需要调整）
        // 或者使用 content.replaceAll("\\s+", "").length() 来排除空白字符
        int totalCharCount = content.length();

        // 计算敏感词长度占总长度的百分比
        double specialCharRate = ((double) sensitiveWordLength / totalCharCount) * 100;

        // 打印敏感词字符率和阈值，方便调试
        log.info("敏感词字符率: {}", String.format("%.3f", specialCharRate));
        log.info("阈值: {}", threshold);

        // 如果敏感词字符率超过阈值，返回true表示需要过滤掉文档
        return specialCharRate > threshold;
    }
    /*
     * ---------------------------------------------------------------
     *              🔖 【 去重配置 】
     * ---------------------------------------------------------------
     */

    /**
     * 相似度去重配置
     *
     * @param contentMap 文本内容列表
     * @param threshold  相似度阈值
     * @return 是否需要去重
     */
    public static List<Long> similarityDeduplication (Map<Long, String> contentMap, double threshold) {
        long l3 = System.currentTimeMillis();
        // 先将 Map 转换为有顺序的 Map，使用 LinkedHashMap 保持插入顺序
        LinkedHashMap<Long, String> sortedContentMap = new LinkedHashMap<>();
        // 将原始内容映射的条目按照键排序，并添加到 sortedContentMap 中
        contentMap.entrySet().stream()
                .sorted(Map.Entry.comparingByKey())
                .forEachOrdered(x -> sortedContentMap.put(x.getKey(), x.getValue()));

        sortedContentMap.forEach((key, value) -> {
            log.info("key:{},value:{}", key, value);
        });
        // 有顺序的转换成文本内容，使用 LinkedList 存储文本内容
        LinkedList<String> contents = sortedContentMap.entrySet().stream()
                .sorted(Comparator.comparing(Map.Entry::getKey))
                .map(Map.Entry::getValue)
                .collect(Collectors.toCollection(LinkedList::new));

        contents.forEach(v -> {
            log.info("value:{}", v);
        });

        // 存储每个文本的 simHash
        LinkedList<String> simHashes = new LinkedList<>();
        // 计算每个文本的 simHash 并添加到 simHashes 中
        for (String content : contents) {
            simHashes.add(HammingUtils.getSimHash(content));
        }


        // 存储相似元素的索引
        List<Long> similarityIndex = new ArrayList<>();
        // 存储相似元素的键
        List<Long> similarityKey = new ArrayList<>();


        // 计算相似性
        for (int i = 0; i < simHashes.size(); i++) {
            // 如果当前元素已经标记为相似，则跳过
            if (similarityIndex.contains((long) i)) {
                continue;
            }
            for (int j = i + 1; j < simHashes.size(); j++) {
                String hash1 = simHashes.get(i);
                String hash2 = simHashes.get(j);
                // 从 1 开始计数，所以 i 和 j 都加 1
                double similarity = HammingUtils.getSimilarity(hash1, hash2);
                // 打印相似性信息
                log.info("第 {} 个元素  和第 {} 个元素  的文本相似度是：{}", i + 1, j + 1, similarity);


                // 如果相似度超过阈值，标记为相似
                if (similarity > threshold) {
                    // 移除相似的文本的索引
                    similarityIndex.add((long) j);

                    // 根据索引位置获取map对应位置的key
                    similarityKey.add(sortedContentMap.keySet().toArray(new Long[0])[j]);
                }
            }
        }
        log.info("相似索引列表：{}", similarityIndex);
        log.info("相似Key列表：{}", similarityKey);

        long l4 = System.currentTimeMillis();
        long diff = l4 - l3;
        long minutes = diff / (60 * 1000);
        long seconds = (diff % (60 * 1000)) / 1000;
        long milliseconds = diff % 1000;

        log.info("总耗时: " + minutes + " 分 " + seconds + " 秒 " + milliseconds + " 毫秒");
        log.info("======================================");

        return similarityKey;

    }

    /*
     * ---------------------------------------------------------------
     *              🔖 【 去隐私配置 】
     * ---------------------------------------------------------------
     */
    // 定义一个正则表达式来匹配电子邮件地址
    private static final String EMAIL_REGEX =
            "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,6}";

    // 编译正则表达式为Pattern对象
    private static final Pattern EMAIL_PATTERN = Pattern.compile(EMAIL_REGEX);

    // 去除文本中的电子邮件地址
    private static String removeEmails (String text) {
        Matcher matcher = EMAIL_PATTERN.matcher(text);
        // 使用空字符串替换匹配的电子邮件地址
        return matcher.replaceAll("");
    }

    /**
     * 去除Email
     * <p>
     * 去除email地址
     *
     * @param content
     */
    public static String processFile (String content) {

        // 去除电子邮件地址
        String modifiedContent = removeEmails(content);

        // 或者打印到控制台以查看结果
        log.info(modifiedContent);
        return modifiedContent;
    }

    // 定义一个正则表达式来匹配IPv4地址
    private static final String IPV4_REGEX =
            "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\." +
            "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\." +
            "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\." +
            "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)";

    // 定义一个正则表达式来匹配IPv6地址
    // 这个正则表达式相对简单，可能无法匹配所有复杂的IPv6地址格式
    // 但它可以匹配常见的IPv6地址，如2001:0db8:85a3:0000:0000:8a2e:0370:7334
    private static final String IPV6_REGEX =
            "([0-9a-fA-F]{1,4}:){7}([0-9a-fA-F]{1,4})";

    // 编译IPv4正则表达式为Pattern对象
    private static final Pattern IPV4_PATTERN = Pattern.compile(IPV4_REGEX);

    // 编译IPv6正则表达式为Pattern对象
    private static final Pattern IPV6_PATTERN = Pattern.compile(IPV6_REGEX);

    /**
     * 去除文本中的IPv4和IPv6地址
     */
    public static String removeIPAddresses (String text) {
        Matcher ipv4Matcher = IPV4_PATTERN.matcher(text);
        text = ipv4Matcher.replaceAll("");
        Matcher ipv6Matcher = IPV6_PATTERN.matcher(text);
        return ipv6Matcher.replaceAll("");
    }

    /**
     * 手机号码的正则表达式
     */
    private static final String MOBILE_REGEX = "1\\d{10}";

    /**
     * 国内电话号码的正则表达式
     */
    private static final String DOMESTIC_PHONE_REGEX = "(\\d{4}-|\\d{3}-)?(\\d{8}|\\d{7})";

    /**
     * 电话号码（400）的正则表达式
     */
    private static final String PHONE_REGEX = "400(-\\d{3,4}){2}|^800(-\\d{3,4}){2}";

    /**
     * 信用卡号的正则表达式
     */
    private static final String CREDIT_CARD_REGEX = "^([1-9]{1})(\\d{15}|\\d{18})$";

    /**
     * 十六进制散列的正则表达式（32或24 位十六进制数，用于 SHA-256 等）
     */
    private static final String HASH_REGEX = "[a-fA-F0-9]{32}|[a-fA-F0-9]{24}";

    // 编译正则表达式为Pattern对象
    private static final Pattern MOBILE_PATTERN = Pattern.compile(MOBILE_REGEX);
    private static final Pattern DOMESTIC_PHONE_PATTERN = Pattern.compile(DOMESTIC_PHONE_REGEX);
    private static final   Pattern PHONE_PATTERN = Pattern.compile(PHONE_REGEX);
    private static final Pattern CREDIT_CARD_PATTERN = Pattern.compile(CREDIT_CARD_REGEX);
    private static final Pattern HASH_PATTERN = Pattern.compile(HASH_REGEX);

    // 定义一个年份格式
    private static final DateTimeFormatter YEAR_FORMAT = DateTimeFormatter.ofPattern("yyyy");

    // 定义一个集合来存储要跳过的年份（这里我们假设跳过当前年份和前几年的范围）
    private static final Set<String> YEARS_TO_SKIP = new HashSet<>();

    static {
        int currentYear = Year.now().getValue();
        for (int i = currentYear - 5; i <= currentYear + 5; i++) {
            YEARS_TO_SKIP.add(String.valueOf(i));
        }
    }

    /**
     * 去除数字
     * <p>
     * 去除数字和字母数字标识符，如电话号码、信用卡号、十六进制散列等，同时跳过年份和简单数字的实例
     *
     * @param text
     * @return
     */
    public static String removeIdentifiers (String text) {
        // 使用正则表达式匹配电话号码
        text = removePhone(text);

        // 使用正则表达式匹配信用卡号
        text = removeCreditCard(text);

        // 使用正则表达式匹配十六进制散列
        text = removeHashMatcher(text);

        //        // 使用StringBuilder和StringBuilder的replace方法去除其他数字，但跳过年份和简单数字
        //        // TODO: 这里目前有bug，先注释掉了。
        //                StringBuilder sb = new StringBuilder(text);
        //                int index = 0;
        //                while ((index = findNextNumberToReplace(sb.toString())) != -1) {
        //                    String number = sb.substring(index, findEndOfNumber(sb.toString(), index));
        //                    if (!isYear(number) && !isSimpleNumber(number)) {
        //                        sb.replace(index, index + number.length(), "");
        //                    }
        //                }
        return text;
    }


    /**
     * 去除电话号码
     *
     * @param text 文本
     * @return 去除电话号码后的文本
     */
    private static String removePhone (String text) {
        // 手机号码的正则表达式
        Matcher mobileMatcher = MOBILE_PATTERN.matcher(text);
        text = mobileMatcher.replaceAll("");

        // 国内电话号码的正则表达式
        Matcher domesticPhoneMatcher = DOMESTIC_PHONE_PATTERN.matcher(text);
        text = domesticPhoneMatcher.replaceAll("");

        // 电话号码（400）的正则表达式
        Matcher phoneMatcher = PHONE_PATTERN.matcher(text);
        text = phoneMatcher.replaceAll("");

        return text;
    }

    /**
     * 去除信用卡号
     *
     * @param text 文本
     * @return 去除信用卡号后的文本
     */
    private static String removeCreditCard (String text) {
        Matcher creditCardMatcher = CREDIT_CARD_PATTERN.matcher(text);
        text = creditCardMatcher.replaceAll("");
        return text;
    }

    /**
     * 去除十六进制散列
     *
     * @param text 文本
     * @return 去除十六进制散列后的文本
     */
    private static String removeHashMatcher (String text) {
        Matcher hashMatcher = HASH_PATTERN.matcher(text);
        text = hashMatcher.replaceAll("");
        return text;
    }

    // 查找下一个要替换的数字的起始索引
    private static int findNextNumberToReplace (String text) {
        // 这里可以添加更复杂的逻辑来定位要替换的数字，但为了简化，我们假设数字以空格或非数字字符分隔
        for (int i = 0; i < text.length(); i++) {
            char c = text.charAt(i);
            if (Character.isDigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) {
                // 找到数字的起始位置
                while (i < text.length() && (Character.isDigit(text.charAt(i)) ||
                                             (text.charAt(i) >= 'a' && text.charAt(i) <= 'f') ||
                                             (text.charAt(i) >= 'A' && text.charAt(i) <= 'F'))) {
                    i++;
                }
                // 返回数字的起始索引（减1，因为我们要在循环外部处理i的递增）
                return i - 1 > 0 ? i - 1 : 0;
            }
        }
        return -1; // 没有找到要替换的数字
    }

    // 找到数字的结束索引
    private static int findEndOfNumber (String text, int startIndex) {
        // 从startIndex开始向后查找，直到遇到非数字字符
        for (int i = startIndex; i < text.length(); i++) {
            if (!(Character.isDigit(text.charAt(i)) ||
                  (text.charAt(i) >= 'a' && text.charAt(i) <= 'f') ||
                  (text.charAt(i) >= 'A' && text.charAt(i) <= 'F'))) {
                return i;
            }
        }
        return text.length(); // 如果字符串以数字结束，则返回字符串的长度
    }

    // 检查一个字符串是否是年份
    private static boolean isYear (String str) {
        try {
            int year = Integer.parseInt(str);
            Year y = Year.parse(str, YEAR_FORMAT);
            return YEARS_TO_SKIP.contains(str);
        } catch (Exception e) {
            return false;
        }
    }

    // 检查一个字符串是否是简单数字（这里假设不超过六位的连续数字）
    private static boolean isSimpleNumber (String str) {
        try {
            int number = Integer.parseInt(str);
            return String.valueOf(number).equals(str) && number >= 0 && number < 1000000;
        } catch (NumberFormatException e) {
            return false;
        }
    }

    public static void main (String[] args) {
        String textWithIdentifiers = "Here are some identifiers: 123-456-7890, 1234567812345678, a1b2c3d4e5f6a1b2c3d4e5f6, 2023, and 987654.";
        // 去除标识符
        String textWithoutIdentifiers = removeIdentifiers(textWithIdentifiers);
        // 打印结果
        log.info(textWithoutIdentifiers);

        //        String traditionalText = "不經意，妳的笑容";
        //        String simplifiedText = traditionalToSimplified(traditionalText);
        //
        //        log.info("繁体文本: [" + traditionalText + "]");
        //        log.info("简体文本: [" + simplifiedText + "]");
        //String dirtyString="?��简体文���f?�G��?��??�G�G��پ?�l?,,,杩欐槸涓€涓\\uE043贡鐮";
        //        // 先进行编码转换
        //        dirtyString = convertEncoding(dirtyString);
        //        // 再进行乱码和无意义 Unicode 字符的清理
        //        String cleanString = clean(dirtyString);
        ////        String s1 = removeNonPrintableUnicodeChars(s);
        //        log.info("去除乱码:[{}]", cleanString);
    }

    public static String clean (String input) {
        // 更广泛的乱码字符范围，包括一些扩展的不可打印字符
        String cleanString = input.replaceAll("[\\x00-\\x1F\\x7F-\\x9F\\uFFFD]", "");
        // 去除无意义的 Unicode 字符，这里范围可根据实际情况修改
        cleanString = cleanString.replaceAll("[\\uE000-\\uF8FF]", "");
        return cleanString;
    }

    public static String convertEncoding (String input) {
        // 尝试多种编码转换，找到正确的编码
        String[] encodings = {"UTF-8", "GBK", "Big5", "ISO-8859-1"};
        for (String encoding : encodings) {
            try {
                byte[] bytes = input.getBytes(encoding);
                String result = new String(bytes, StandardCharsets.UTF_8);
                return result;
            } catch (Exception e) {
                // 编码转换失败，继续尝试下一个编码
                continue;
            }
        }
        return input;
    }
}
