All Downloads are FREE. Search and download functionalities are using the official Maven repository.

shz.core.PathMatcher Maven / Gradle / Ivy

There is a newer version: 2024.0.2
Show newest version
package shz.core;

public final class PathMatcher {
    // 匹配的path为以/分割的多级路径
    // *匹配一个任意字符
    // **匹配任意个任意字符
    // /*/匹配一个目录
    // /**/匹配一个或多个目录

    private final char[] pattern;
    private final int length;
    private final int lastSp;
    private final int spLen;
    private final int[][] sps;

    public PathMatcher(char[] pattern) {
        this.pattern = pattern;
        length = this.pattern.length;
        int pl = lastSp(this.pattern);
        lastSp = pl == -1 ? 0 : pl + 1;
        spLen = spLen(this.pattern);
        sps = sps(this.pattern, spLen);
    }

    private int lastSp(char[] array) {
        for (int i = array.length - 1; i >= 0; --i) if (array[i] == '/') return i;
        return -1;
    }

    private int spLen(char[] array) {
        int len = 1;
        int idx = 0;
        while ((idx = nextSp(array, idx)) != -1) ++len;
        return len;
    }

    private int nextSp(char[] array, int idx) {
        for (int i = idx + 1; i < array.length; ++i) if (array[i] == '/') return i;
        return -1;
    }

    private int[][] sps(char[] array, int len) {
        int[][] sps = new int[len][];
        for (int i = 0; i < len; ++i) sps[i] = new int[2];
        sps[0][0] = array[0] == '/' ? 1 : 0;
        sps[0][1] = nextSp(array, sps[0][0]);
        if (sps[0][1] == -1) sps[0][1] = array.length;
        else if (len > 1) {
            for (int i = 1; i < len; ++i) {
                sps[i][0] = sps[i - 1][1] + 1;
                sps[i][1] = nextSp(array, sps[i][0]);
            }
            if (sps[len - 1][1] == -1) sps[len - 1][1] = array.length;
        }
        return sps;
    }

    public PathMatcher(String pattern) {
        this(format(pattern));
    }

    public static char[] format(String pattern) {
        int len = pattern.length();
        StringBuilder sb = new StringBuilder(len);
        char prev1 = ' ', prev2 = ' ', prev3 = ' ', prev4 = ' ', prev5;
        int mark = 0;
        char c;
        for (int i = 0; i < len; ++i) {
            c = pattern.charAt(i);
            if (c == '/' || c == '\\') {
                if (prev1 == '/') continue;
                c = '/';
            } else if (c == '*' && prev1 == '*' && prev2 == '*') continue;
            prev5 = prev4;
            prev4 = prev3;
            prev3 = prev2;
            prev2 = prev1;
            prev1 = c;

            if (mark == 0) {
                if (prev1 == '*' && prev2 == '/' && prev3 == '*' && prev4 == '*' && (prev5 == '/' || prev5 == ' '))
                    mark = 1;
                else sb.append(prev1);
            } else if (mark == 1) {
                if (prev1 == '*') mark = 2;
                else {
                    sb.append(prev2).append(prev1);
                    mark = 0;
                }
            } else {
                if (prev1 != '/') sb.append(prev3).append(prev2).append(prev1);
                mark = 0;
            }
        }
        char[] chars = new char[sb.length()];
        sb.getChars(0, chars.length, chars, 0);
        return chars;
    }

    public boolean isMatch(char[] path) {
        int checkTail = checkTail(path);
        if (checkTail == N) return false;
        if (spLen == 1) return checkTail == S || spLen(path) == 1;
        int checkHead = checkHead(path);
        if (checkHead == N) return false;
        if (spLen == 2) return checkTail == S || checkHead == S || spLen(path) == 2;
        int pSpLen = spLen(path);
        int[][] pSps = sps(path, pSpLen);
        int[][] dp = new int[pSpLen][spLen];
        dp[0][0] = checkHead;
        dp[0][0] |= OK;
        for (int i = 1; i < pSpLen; ++i) {
            dp[i][0] = match(path, pSps[i][0], pSps[i][1], pattern, sps[0][0], sps[0][1]);
            if (dp[i][0] == N) break;
            dp[i][0] |= OK;
        }
        for (int j = 1; j < spLen; ++j) {
            dp[0][j] = match(path, pSps[0][0], pSps[0][1], pattern, sps[j][0], sps[j][1]);
            if (dp[0][j] == N) break;
            dp[0][j] |= OK;
        }
        for (int i = 1; i < pSpLen; ++i) {
            for (int j = 1; j < spLen; ++j) {
                dp[i][j] = match(path, pSps[i][0], pSps[i][1], pattern, sps[j][0], sps[j][1]);
                if (dp[i][j] != N) {
                    dp[i][j] |= dp[i - 1][j - 1];
                    if ((dp[i][j] & S) != 0 || (dp[i][j - 1] & S) != 0) {
                        dp[i][j] |= dp[i][j - 1];
                        dp[i][j] |= dp[i - 1][j];
                    }
                }
            }
        }
        return (dp[pSpLen - 1][spLen - 1] & OK) != 0;
    }

    private int checkTail(char[] path) {
        return length < 2 ? N : match(path, lastSp(path) + 1, path.length, pattern, lastSp, length);
    }

    private int checkHead(char[] path) {
        int[][] pSps = sps(path, 1);
        return match(path, pSps[0][0], pSps[0][1], pattern, sps[0][0], sps[0][1]);
    }

    private static final int N = 1;
    private static final int M = 1 << 1;
    private static final int S = 1 << 2;
    private static final int OK = 1 << 3;

    private static int match(char[] path, int FL, int FR, char[] pattern, int PL, int PR) {
        if (path[FR - 1] != pattern[PR - 1] && pattern[PR - 1] != '*') return N;
        if (path[FL] != pattern[PL] && pattern[PL] != '*') return N;

        if (PR - PL == 1) return pattern[PL] == '*' ? M : FR - FL > 1 || path[FL] != pattern[PL] ? N : M;
        if (PR - PL == 2) {
            if (pattern[PL] == '*' && pattern[PL + 1] == '*') return S;
            if (FR - FL != 2) return N;
            if (pattern[PL + 1] == '*') return path[FL] == pattern[PL] ? M : N;
            if (pattern[PL] == '*') return path[FL + 1] == pattern[PL + 1] ? M : N;
            return path[FL] == pattern[PL] && path[FL + 1] == pattern[PL + 1] ? M : N;
        }
        boolean[][] dp = new boolean[FR - FL][PR - PL];
        dp[0][0] = true;
        for (int i = 1; i < FR - FL; ++i) {
            for (int j = 1; j < PR - PL; ++j) {
                if (path[i + FL] == pattern[j + PL] || pattern[j + PL] == '*') {
                    dp[i][j] |= dp[i - 1][j - 1];
                    if (pattern[j - 1 + PL] == '*' && (pattern[j + PL] == '*' || (j >= 2 && pattern[j - 2 + PL] == '*'))) {
                        dp[i][j] |= dp[i][j - 1];
                        dp[i][j] |= dp[i - 1][j];
                    }
                }
            }
        }
        return dp[FR - FL - 1][PR - PL - 1] ? M : N;
    }

    public boolean isMatch(String path) {
        return isMatch(path.toCharArray());
    }

    public char[] getPattern() {
        return pattern;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy