Java中使用*与#通配符实现主题匹配的问题排查
修复井号(#)通配符的主题匹配逻辑
你的代码里#通配符失效的核心问题有两个:
- 只对比了分段长度相同的主题,但#的设计目标是匹配当前层级及所有子层级,比如
t1.#需要匹配t1.t3.t5这种更长的主题 - 对#的处理逻辑不符合发布订阅主题的规则:#必须是主题的最后一个分段,且匹配到#后,后续所有层级都直接视为匹配
修改后的完整代码
public List<Topic> getMatchingTopics(Topic topic, List<Topic> currentTopics) { List<Topic> matchingTopics = new ArrayList<>(); String topicString = topic.getName(); String[] topicSegments = topicString.split("\\."); boolean hasHash = false; boolean hasStar = false; // 提前检查#的合法性:如果有#,必须是最后一个分段 if (topicSegments.length > 0 && topicSegments[topicSegments.length - 1].equals("#")) { hasHash = true; // 如果#不是唯一的分段,前面不能有其他通配符(可选,根据业务规则调整) for (int i = 0; i < topicSegments.length - 1; i++) { if (topicSegments[i].equals("*") || topicSegments[i].equals("#")) { return matchingTopics; // 非法格式直接返回空 } } } else { // 检查是否包含*通配符 for (String seg : topicSegments) { if (seg.equals("*")) { hasStar = true; break; } } } for (Topic t : currentTopics) { String currentTopicString = t.getName(); // 完全匹配的情况直接加入结果 if (topicString.equals(currentTopicString)) { matchingTopics.add(t); continue; } String[] currentSegments = currentTopicString.split("\\."); if (hasHash) { // #的匹配逻辑:前缀分段完全匹配,且当前主题分段数不少于前缀长度 int hashPrefixLength = topicSegments.length - 1; if (currentSegments.length < hashPrefixLength) { continue; } boolean match = true; for (int i = 0; i < hashPrefixLength; i++) { if (!topicSegments[i].equals(currentSegments[i])) { match = false; break; } } if (match) { matchingTopics.add(t); } } else if (hasStar) { // *的匹配逻辑:分段长度相等,每个分段要么是*要么完全匹配 if (topicSegments.length != currentSegments.length) { continue; } boolean match = true; for (int i = 0; i < topicSegments.length; i++) { if (topicSegments[i].equals("*")) { continue; } if (!topicSegments[i].equals(currentSegments[i])) { match = false; break; } } if (match) { matchingTopics.add(t); } } } return matchingTopics; }
关键修改说明
- #合法性校验:提前判断#是否在主题末尾,避免
t1.#.t2这类非法格式的主题干扰匹配(如果业务允许特殊格式可删除此校验) - #专属匹配逻辑:
- 提取#前面的前缀分段(比如
t1.#的前缀是t1) - 只要待匹配主题的分段数不少于前缀长度,且前缀完全匹配,就视为匹配
- 这样
t1.t2(2段)、t1.t3.t5(3段)都会被t1.#命中
- 提取#前面的前缀分段(比如
- 拆分通配符处理:把#和*的匹配逻辑分开,避免互相干扰,代码可读性更强
- 提前提取通配符信息:在循环外部先判断查询主题的通配符类型,避免每次循环重复拆分和判断
测试验证
运行你的测试方法后,t1.#会输出全部5个主题,t1.*会输出t1.t2、t1.t3、t1.t4三个主题,完全符合预期。
内容的提问来源于stack exchange,提问作者wazowski
相关产品推荐
相关产品推荐

