当前位置: 首页 > news >正文

通配符对称冲突检测工具

package com.ldj.springboot.importbean.config;import lombok.extern.slf4j.Slf4j;import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;/*** 通配符模糊对称冲突检测工具类* 支持:* - 纯数字:  如 "1001"* - 前缀模糊:如 "1001*"* - 后缀模糊:如 "*10"* - 中间通配:如 "10*1"* - 全匹配:  如 "*"* 不支持:包含多个 '*'*/
@Slf4j
public class WildcardPatternUtil {// 缓存解析结果,提升性能private static final Map<String, PatternInfo> CACHE = new ConcurrentHashMap<>();/*** 判断两个模糊是否可能匹配同一个字符串(即:冲突)*/public static boolean isConflict(String p1, String p2) {if (p1 == null || p2 == null) {return false;}PatternInfo info1 = parsePattern(p1);PatternInfo info2 = parsePattern(p2);boolean prefixOk = isPrefixCompatible(info1.prefix, info2.prefix);boolean suffixOk = isSuffixCompatible(info1.suffix, info2.suffix);log.debug("模糊冲突检测: '{}' vs '{}' -> 前缀:{} 后缀:{} 结果:{}", p1, p2, prefixOk, suffixOk, prefixOk && suffixOk);return prefixOk && suffixOk;}/*** 检查给定模糊 p1 是否与 patterns 列表中的任意一个模糊冲突*/public static boolean isConflictWithAny(String p1, List<String> patterns) {if (p1 == null || patterns == null || patterns.isEmpty()) {return false;}return patterns.stream().anyMatch(p -> isConflict(p1, p));}/*** 解析模糊为前缀和后缀* 缓存结果以提升性能*/private static PatternInfo parsePattern(String pattern) {return CACHE.computeIfAbsent(pattern, k -> {if (k == null || k.isEmpty()) {return new PatternInfo("", "");}int firstStar = k.indexOf('*');int lastStar = k.lastIndexOf('*');// 检查是否包含多个'*'if (firstStar != lastStar) {throw new IllegalArgumentException("Pattern cannot contain multiple '*' : " + k);}if (firstStar == -1) {// 纯数字:精确匹配,前缀和后缀都设为整个字符串return new PatternInfo(k, k);}String prefix = k.substring(0, firstStar);String suffix = (firstStar + 1 < k.length()) ? k.substring(firstStar + 1) : "";return new PatternInfo(prefix, suffix);});}/*** 判断两个前缀是否兼容* 规则:较短的是较长的前缀,或任意一个为空(表示 *xxx)*/private static boolean isPrefixCompatible(String pre1, String pre2) {if (pre1.isEmpty() || pre2.isEmpty()) {return true; // 有一个是 *xxx 形式,总是兼容}return pre1.startsWith(pre2) || pre2.startsWith(pre1);}/*** 判断两个后缀是否兼容* 规则:较短的是较长的后缀,或任意一个为空(表示 xxx*)*/private static boolean isSuffixCompatible(String suf1, String suf2) {if (suf1.isEmpty() || suf2.isEmpty()) {return true; // 有一个是 xxx* 形式,总是兼容}return suf1.endsWith(suf2) || suf2.endsWith(suf1);}// 内部类:存储模糊的前缀和后缀private static class PatternInfo {final String prefix;final String suffix;PatternInfo(String prefix, String suffix) {this.prefix = prefix;this.suffix = suffix;}}// ========== 测试用例 ==========public static void main(String[] args) {String p1 = "10*1";// 测试1: 纯数字 vs 模糊List<String> patterns1 = Collections.singletonList("1001");boolean conflict1 = isConflictWithAny(p1, patterns1);System.out.println("10*1 与 1001 冲突? " + conflict1); // true// 测试2: 1* 是前缀模糊List<String> patterns2 = Collections.singletonList("1*");boolean conflict2 = isConflictWithAny(p1, patterns2);System.out.println("10*1 与 1* 冲突? " + conflict2); // true// 测试3: 20*1 不冲突List<String> patterns3 = Collections.singletonList("20*1");boolean conflict3 = isConflictWithAny(p1, patterns3);System.out.println("10*1 与 20*1 冲突? " + conflict3); // false// 测试4: 1001* 前缀模糊List<String> patterns4 = Collections.singletonList("1001*");boolean conflict4 = isConflictWithAny(p1, patterns4);System.out.println("10*1 与 1001* 冲突? " + conflict4); // true (因为 10011 匹配两者)// 测试5: *10 后缀模糊List<String> patterns5 = Collections.singletonList("*10");boolean conflict5 = isConflictWithAny(p1, patterns5);System.out.println("10*1 与 *10 冲突? " + conflict5); // false// 测试6: 纯数字不冲突List<String> patterns6 = Collections.singletonList("2002");boolean conflict6 = isConflictWithAny(p1, patterns6);System.out.println("10*1 与 2002 冲突? " + conflict6); // false// 测试7: * 全匹配List<String> patterns7 = Collections.singletonList("*");boolean conflict7 = isConflictWithAny(p1, patterns7);System.out.println("10*1 与 * 冲突? " + conflict7); // true// 测试8: * 多个List<String> patterns8 = Collections.singletonList("101");boolean conflict8 = isConflictWithAny("10*1*", patterns8);System.out.println("10*1*与101冲突? " + conflict8); // true}
}

 

package com.ldj.springboot.importbean.config;

 

import lombok.extern.slf4j.Slf4j;

import java.util.Map;

import java.util.concurrent.ConcurrentHashMap;

 

@Slf4j

public class WildcardPatternUtil {

 

    private static final Map<String, PatternInfo> CACHE = new ConcurrentHashMap<>();

 

    /**

     * 判断两个模式是否冲突(即存在至少一个字符串能被两者匹配)

     */

    public static boolean isConflict(String p1, String p2) {

        if (p1 == null || p2 == null || p1.isEmpty() || p2.isEmpty()) {

            return false;

        }

 

        PatternInfo a = parsePattern(p1);

        PatternInfo b = parsePattern(p2);

 

        // 1. 都是精确匹配

        if (!a.hasWildcard && !b.hasWildcard) {

            return p1.equals(p2);

        }

 

        // 2. 一个是精确,另一个是模糊

        if (!a.hasWildcard) {

            return matches(b, p1);

        }

        if (!b.hasWildcard) {

            return matches(a, p2);

        }

 

        // 3. 两个都是模糊:判断是否有交集

        return canIntersect(a, b);

    }

 

    // ==================== 解析 ====================

    private static PatternInfo parsePattern(String pattern) {

        return CACHE.computeIfAbsent(pattern, PatternInfo::new);

    }

 

    private static class PatternInfo {

        final String prefix; // *之前的部分

        final String suffix; // *之后的部分

        final boolean hasWildcard;

 

        PatternInfo(String pattern) {

            int star = pattern.indexOf('*');

            if (star == -1) {

                prefix = pattern;

                suffix = pattern;

                hasWildcard = false;

            } else {

                if (pattern.lastIndexOf('*') != star) {

                    throw new IllegalArgumentException("Multiple wildcards not supported: " + pattern);

                }

                prefix = pattern.substring(0, star);

                suffix = (star + 1 < pattern.length()) ? pattern.substring(star + 1) : "";

                hasWildcard = true;

            }

        }

    }

 

    // ==================== 精确判断是否匹配 ====================

    /**

     * 判断模糊模式 info 是否匹配目标字符串 str

     */

    private static boolean matches(PatternInfo info, String str) {

        if (!str.startsWith(info.prefix)) {

            return false;

        }

        if (!info.suffix.isEmpty() && !str.endsWith(info.suffix)) {

            return false;

        }

        // 检查前后缀是否重叠且一致

        int minLen = info.prefix.length() + info.suffix.length();

        if (str.length() < minLen) {

            return false;

        }

        // 重叠部分检查

        int suffixStart = str.length() - info.suffix.length();

        int prefixEnd = info.prefix.length();

        if (suffixStart < prefixEnd) {

            String overlapStr = str.substring(suffixStart, prefixEnd);

            String suffixPrefixPart = info.suffix.substring(0, prefixEnd - suffixStart);

            return overlapStr.equals(suffixPrefixPart);

        }

        return true;

    }

 

    // ==================== 两个模糊模式是否有交集 ====================

    /**

     * 判断两个模糊模式是否可能匹配同一个字符串

     */

    private static boolean canIntersect(PatternInfo a, PatternInfo b) {

        String ap = a.prefix, as = a.suffix;

        String bp = b.prefix, bs = b.suffix;

 

        // 1. 前缀兼容性

        if (!isPrefixCompatible(ap, bp)) {

            return false;

        }

 

        // 2. 后缀兼容性

        if (!isSuffixCompatible(as, bs)) {

            return false;

        }

 

        // 3. 最小长度:是否存在足够长的字符串满足前后缀?

        int minLenA = ap.length() + as.length();

        int minLenB = bp.length() + bs.length();

        int requiredMinLen = Math.max(minLenA, minLenB);

 

        // 4. 构造合并后的前缀和后缀

        String mergedPrefix = getLongerOrCommon(ap, bp, true);

        String mergedSuffix = getLongerOrCommon(as, bs, false);

 

        // 5. 检查合并后的前后缀是否自身冲突(重叠部分是否一致)

        return !isSelfConflicting(mergedPrefix, mergedSuffix);

    }

 

    // 前缀是否兼容:一个包含另一个

    private static boolean isPrefixCompatible(String a, String b) {

        return a.startsWith(b) || b.startsWith(a);

    }

 

    // 后缀是否兼容:一个包含另一个

    private static boolean isSuffixCompatible(String a, String b) {

        return a.endsWith(b) || b.endsWith(a);

    }

 

    // 获取更长的(或共同的)前缀或后缀

    private static String getLongerOrCommon(String a, String b, boolean isPrefix) {

        if (isPrefix) {

            return a.startsWith(b) ? a : b.startsWith(a) ? b : null;

        } else {

            return a.endsWith(b) ? a : b.endsWith(a) ? b : null;

        }

    }

 

    /**

     * 检查 mergedPrefix 和 mergedSuffix 是否自身冲突(即无法共存于同一字符串)

     */

    private static boolean isSelfConflicting(String pre, String suf) {

        int total = pre.length() + suf.length();

        int maxLen = Math.max(pre.length(), suf.length());

        if (total <= maxLen) {

            // 完全重叠

            String shorter = pre.length() < suf.length() ? pre : suf;

            String longer = pre.length() < suf.length() ? suf : pre;

            String pos = pre.length() < suf.length() ? "suffix" : "prefix";

            if ("prefix".equals(pos)) {

                return !longer.startsWith(shorter);

            } else {

                return !longer.endsWith(shorter);

            }

        } else {

            // 部分重叠或无重叠

            int sufStart = total - suf.length(); // 在总串中 suffix 的起始位置

            int preEnd = pre.length();

            if (sufStart < preEnd) {

                // 重叠区域

                String preOverlap = pre.substring(sufStart, preEnd);

                String sufOverlap = suf.substring(0, preEnd - sufStart);

                return !preOverlap.equals(sufOverlap);

            }

            // 无重叠,总是可以构造

            return false;

        }

    }

}

 

http://www.dtcms.com/a/509553.html

相关文章:

  • Linux小课堂: 数据处理核心命令之grep、sort、wc、uniq 与 cut 的深度解析
  • 深圳建筑设计平台网站wordpress wp posts
  • 北京住房和城乡建设官方网站色彩搭配比较好的网站
  • 找到网站后台地址如何做自己网站
  • 有没有人做网站大学做html个人网站素材
  • 嘉兴五县两区网站建设局机关网站建设
  • 江苏省交通建设厅门户网站wordpress如何修改首页文件模板
  • 如何建立一个网站详细步骤通辽住房和城乡建设厅网站
  • 网站设计需要多少钱小程序开发教程 下载
  • 公司无网站无平台怎么做外贸2021最火关键词
  • 手机网站的静态页面官网站站
  • 蒙古网站后缀国内知名设计工作室
  • 单页网站怎么制作昆明企业网站建设公司
  • 建设银行兰州分行网站百度小程序开发平台
  • 朝阳网站建设 慈云寺厦门易尔通网站建设好吗
  • 网站 备案 哪个省建设培训中心网站
  • 成都大型网站建设公司iis网站属性在哪
  • 中国站长查询域名备案西安有哪些做网站的公司好
  • 东莞定制网站建设jsp网站部署怎么做
  • 百度推广太原网站建设阿里云服务器添加网站
  • 2016网站优化今天深圳新增确诊最新消息
  • 驾校官方网站 模板wordpress手动装插件
  • 怎样直接输入网址打开网站ps做网站标签
  • 甘肃肃第八建设集团网站1wordpress关联adsense
  • 长沙做网站开发多少钱服务行业做网站
  • 大学生免费ppt网站长沙网站制作工作室
  • 西宁吧 百度贴吧网站优化反馈机制 seo
  • 哪些网站可以做兼职设计建网站和开发app哪个难
  • 网页制作与网站建设06627网站建设 王卫洲
  • 网站背景动图怎么做2022年新闻热点摘抄