理论上每个字符只会被使用到一次,从而保证算法的时间复杂度,满足mqtt协议的“+”、“#”通配符要求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129

/**
* @author 刘靖
*/
public class TopicUtils {

public static void main(String[] args) {
// 规则topic
String topicRule = "aa/+/bb/+/+/cc/#";
// 目标topic
String topic = "aa/11/bb/2222/4444/cc/5555//";
System.out.println("是否匹配:" + match(topicRule, topic));

topicRule = "+";
topic = "aa";
System.out.println("是否匹配:" + match(topicRule, topic));

topicRule = "+/#";
topic = "aa/cc/dd";
System.out.println("是否匹配:" + match(topicRule, topic));

topicRule = "/+/";
topic = "/aa/";
System.out.println("是否匹配:" + match(topicRule, topic));

topicRule = "aa/#";
topic = "aa";
System.out.println("是否匹配:" + match(topicRule, topic));
}

/**
* 匹配mqtt topic
* @param topicRule 匹配规则
* @param topic 目标topic
* @return
*/
public static boolean match(String topicRule, String topic) {
char[] topicRuleChar = topicRule.toCharArray();
char[] topicChar = topic.toCharArray();
// topic的字符指针,用来表示当前判断到了哪个位置的字符
int topicIndex = 0;

ruleSign:
for (int i = 0; i < topicRuleChar.length; i++) {

char indexRuleChar = topicRuleChar[i];

// 如果满足 '/#' 格式,则说明topic匹配
if (indexRuleChar == '#' && topicRuleChar[i - 1] == '/'){
return true;
}

// 如果已经到达目标字符串末尾,但是规则字符串当前还不是通配符 '+' 则表示匹配失败
if (topicIndex == topicChar.length){
if (i + 2 == topicRuleChar.length && topicRuleChar[i] == '/' && topicRuleChar[i + 1] == '#'){
return true;
}
if (indexRuleChar != '+'){
return false;
}
}
// 判断当前字符是否相等,如果相等直接跳到下一个字符,并向后移动一格topicIndex指针
if (topicIndex != topicChar.length && indexRuleChar == topicChar[topicIndex]){
topicIndex++;
continue;
}

/*
'+' 符号通配符判断,如果当前字符为+号,有四种情况满足单层通配符要求:
1.当前字符为第一个字符,且后一个字符为 '/'
2.当前字符为中间字符,且前后字符均为 '/'
3.当前字符未末尾字符,且前一个字符未 '/'
4.整个字符串都只有当前一个字符
*/
if (indexRuleChar == '+'){
if (topicRuleChar.length == 1){
// 满足整个topicRule = '+'
// 判断topic是否为单层,不为单层直接不匹配(遇到'/'符号表示不匹配)
for (int j = 0; j < topicChar.length; j++) {
if (topicChar[j] == '/'){
return false;
}
}
return true;
}else if (i == 0 && topicRuleChar[i + 1] == '/'){
// 满足topicRule = '+/' 开头
// 将topicIndex指针移动到下一个'/'符号位置,并结束当前判断
for (int j = topicIndex; j < topicChar.length; j++) {
if (topicChar[j] == '/'){
topicIndex = j;
continue ruleSign;
}
}
return false;
}else if (i != 0 && topicRuleChar[i - 1] == '/'){
if (topicRuleChar.length - 1 <= i){
// 满足topicRule 以 '/+' 结尾
// 但凡后面还有 '/' 符号,代表不匹配
for (int j = topicIndex; j < topicChar.length; j++) {
if (topicChar[j] == '/'){
return false;
}
}
return true;
}else if (topicRuleChar[i + 1] == '/'){
// 满足topicRule 包含 '/+/'
for (int j = topicIndex; j < topicChar.length; j++) {
if (topicChar[j] == '/'){
topicIndex = j;
continue ruleSign;
}
}
return false;
}
}
}
// 不满足'+'通配符
return false;
}
// 如果判断完rule的每个字符,目标topic还未到达尾部,则说明不匹配
if (topicIndex < topicChar.length){
return false;
}
return true;
}


}