antpathmatcher遇到* ** ?源码详细实现
时间: 2023-07-23 11:34:27 浏览: 188
antpathmatcher 是 Spring 框架中一个用于处理路径匹配的工具类,其主要功能是将一个给定的字符串与一个指定的模式进行匹配。在模式中,用户可以使用一些特殊的字符,比如 ? 和 *,来表示匹配任意字符和任意路径段。
在 antpathmatcher 中,* 和 ** 的含义如下:
- * 匹配任意字符(除了路径分隔符 /);
- ** 匹配任意路径段,可以是空路径段。
下面是 antpathmatcher 中关于 * 和 ** 的匹配实现:
```java
public boolean match(String pattern, String path) {
if (path.startsWith(this.pathSeparator) != pattern.startsWith(this.pathSeparator)) {
return false;
}
String[] pattDirs = StringUtils.tokenizeToStringArray(pattern, this.pathSeparator, this.trimTokens, true);
String[] pathDirs = StringUtils.tokenizeToStringArray(path, this.pathSeparator, this.trimTokens, true);
int pattIdxStart = 0;
int pattIdxEnd = pattDirs.length - 1;
int pathIdxStart = 0;
int pathIdxEnd = pathDirs.length - 1;
// Match all elements up to the first **
while (pattIdxStart <= pattIdxEnd && pathIdxStart <= pathIdxEnd) {
String pattDir = pattDirs[pattIdxStart];
if ("**".equals(pattDir)) {
break;
}
if (!matchStrings(pattDir, pathDirs[pathIdxStart])) {
return false;
}
pattIdxStart++;
pathIdxStart++;
}
// If there was no ** pattern, and the path is shorter or longer than the pattern, return false
if (pathIdxStart > pathIdxEnd) {
// Path is exhausted, only match if rest of pattern is * or **'s
if (pattIdxStart > pattIdxEnd) {
return (pattern.endsWith(this.pathSeparator) ? path.endsWith(this.pathSeparator) :
!path.endsWith(this.pathSeparator));
}
if (!this.endsWith(pattDirs[pattIdxEnd], this.allPattern)) {
return false;
}
return (pattIdxStart == pattIdxEnd && path.endsWith(this.pathSeparator)) || matchStrings(pattDirs, pattIdxStart, pattIdxEnd, pathDirs, pathIdxStart - 1);
}
else if (pattIdxStart > pattIdxEnd) {
// String not exhausted, but pattern is. Failure.
return false;
}
else if (!this.ignoreAll(pattDirs, pattIdxStart, pattIdxEnd)) {
return false;
}
// Pattern contains **, full match guaranteed
if ("**".equals(pattDirs[pattIdxStart]) || "**".equals(pattDirs[pattIdxEnd])) {
return true;
}
// Match pattern to end in the path
while (pattIdxStart <= pattIdxEnd && pathIdxStart <= pathIdxEnd) {
String pattDir = pattDirs[pattIdxEnd];
if ("**".equals(pattDir)) {
break;
}
if (!matchStrings(pattDir, pathDirs[pathIdxEnd])) {
return false;
}
pattIdxEnd--;
pathIdxEnd--;
}
return (pathIdxStart > pathIdxEnd) || matchStrings(pattDirs, pattIdxStart, pattIdxEnd, pathDirs, pathIdxStart);
}
private boolean matchStrings(String pattern, String str) {
return this.stringMatcher.match(pattern, str);
}
private boolean matchStrings(String[] pattDirs, int pattStart, int pattEnd, String[] strDirs, int strStart) {
int patIdxStart = pattStart;
int patIdxEnd = pattEnd;
int strIdxStart = strStart;
int strIdxEnd = strDirs.length - 1;
while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
String patDir = pattDirs[patIdxEnd];
if ("**".equals(patDir)) {
break;
}
if (!matchStrings(patDir, strDirs[strIdxEnd])) {
return false;
}
patIdxEnd--;
strIdxEnd--;
}
if (strIdxStart > strIdxEnd) {
// String is exhausted
for (int i = patIdxStart; i <= patIdxEnd; i++) {
if (!this.ignore(pattDirs[i])) {
return false;
}
}
return true;
}
else {
if (patIdxStart > patIdxEnd) {
// String not exhausted, but pattern is. Failure.
return false;
}
}
while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
int patIdxTmp = -1;
for (int i = patIdxStart + 1; i <= patIdxEnd; i++) {
if (this.allPattern.equals(pattDirs[i])) {
patIdxTmp = i;
break;
}
}
if (patIdxTmp == patIdxStart + 1) {
// '**/**' situation, so skip one
patIdxStart++;
continue;
}
// Find the next pattern part in pattern
int patLength = (patIdxTmp - patIdxStart - 1);
int strLength = (strIdxEnd - strIdxStart + 1);
int foundIdx = -1;
strLoop:
for (int i = strIdxStart; i <= strIdxEnd - patLength; i++) {
for (int j = 0; j < patLength; j++) {
String subPat = (j + patIdxStart + 1 < patIdxTmp ? pattDirs[j + patIdxStart + 1] : null);
String subStr = strDirs[i + j];
if (!matchStrings(subPat, subStr)) {
continue strLoop;
}
}
foundIdx = i;
break;
}
if (foundIdx == -1) {
return false;
}
patIdxStart = patIdxTmp;
strIdxStart = foundIdx + patLength;
}
for (int i = patIdxStart; i <= patIdxEnd; i++) {
if (!this.ignore(pattDirs[i])) {
return false;
}
}
return true;
}
```
在这段代码中,我们可以看到 antpathmatcher 的匹配实现是基于递归的。它将模式和路径都分解成一个个的路径段,然后在逐个匹配这些路径段。如果遇到 *,则匹配任意一个非路径分隔符的字符,如果遇到 **,则匹配任意的路径段,包括空路径段。
具体来说,这段代码实现了以下几个步骤:
1. 根据路径分隔符将模式和路径分解成一个个的路径段;
2. 逐个匹配模式和路径的路径段;
3. 如果遇到 **,则跳过中间的路径段,直接匹配后面的路径段;
4. 如果模式匹配成功,则返回 true,否则返回 false。
总的来说,antpathmatcher 的匹配实现相对较为复杂,但是能够处理各种情况下的路径匹配问题,而且在 Spring 框架中得到了广泛的应用。
阅读全文