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

com.yahoo.jdisc.application.GlobPattern Maven / Gradle / Ivy

// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.jdisc.application;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

/**
 * @author Simon Thoresen Hult
 */
class GlobPattern implements Comparable {

    private static final GlobPattern WILDCARD = new WildcardPattern();
    protected final String[] parts;

    private GlobPattern(String... parts) {
        this.parts = parts;
    }

    public final Match match(String text) {
        return match(text, 0);
    }

    public Match match(String text, int offset) {
        int[] pos = new int[parts.length - 1 << 1];
        if (!matches(text, offset, 0, pos)) {
            return null;
        }
        return new Match(text, pos);
    }

    private boolean matches(String text, int textIdx, int partIdx, int[] out) {
        String part = parts[partIdx];
        if (partIdx == parts.length - 1 && part.isEmpty()) {
            out[partIdx - 1 << 1 | 1] = text.length();
            return true; // optimize trailing wildcard
        }
        int partEnd = textIdx + part.length();
        if (partEnd > text.length()|| !text.startsWith(part, textIdx))  {
            return false;
        }
        if (partIdx == parts.length - 1) {
            return partEnd == text.length();
        }
        out[partIdx << 1] = partEnd;
        for (int i = partEnd; i <= text.length(); ++i) {
            out[partIdx << 1 | 1] = i;
            if (matches(text, i, partIdx + 1, out)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public int compareTo(GlobPattern rhs) {
        // wildcard pattern always orders last
        if (parts.length == 0 || rhs.parts.length == 0) {
            return rhs.parts.length - parts.length;
        }
        // next is trailing wildcard
        int cmp = compare(parts[parts.length - 1], rhs.parts[rhs.parts.length - 1], false);
        if (cmp != 0) {
            return cmp;
        }
        // then comes part comparison
        for (int i = 0; i < parts.length && i < rhs.parts.length; ++i) {
            cmp = compare(parts[i], rhs.parts[i], true);
            if (cmp != 0) {
                return cmp;
            }
        }
        // one starts with the other, sort longest first
        return rhs.parts.length - parts.length;
    }

    private static int compare(String lhs, String rhs, boolean compareNonEmpty) {
        if ((lhs.isEmpty() || rhs.isEmpty()) && !lhs.equals(rhs)) {
            return rhs.length() - lhs.length();
        }
        if (!compareNonEmpty) {
            return 0;
        }
        return rhs.compareTo(lhs);
    }

    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof GlobPattern)) {
            return false;
        }
        GlobPattern rhs = (GlobPattern)obj;
        if (!Arrays.equals(parts, rhs.parts)) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        return Arrays.hashCode(parts);
    }

    @Override
    public String toString() {
        StringBuilder ret = new StringBuilder();
        for (int i = 0; i < parts.length; ++i) {
            ret.append(parts[i]);
            if (i < parts.length - 1) {
                ret.append("*");
            }
        }
        return ret.toString();
    }

    public static Match match(String glob, String text) {
        return compile(glob).match(text);
    }

    public static GlobPattern compile(String pattern) {
        if (pattern.equals("*")) {
            return WILDCARD;
        }
        if (pattern.indexOf('*') < 0) {
            return new VerbatimPattern(pattern);
        }
        List arr = new LinkedList<>();
        for (int prev = 0, next = 0; next <= pattern.length(); ++next) {
            if (next == pattern.length() || pattern.charAt(next) == '*') {
                arr.add(pattern.substring(prev, next));
                prev = next + 1;
            }
        }
        return new GlobPattern(arr.toArray(new String[arr.size()]));
    }

    public static class Match {

        private final String str;
        private final int[] pos;

        private Match(String str, int[] pos) {
            this.str = str;
            this.pos = pos;
        }

        public int groupCount() {
            return pos.length >> 1;
        }

        public String group(int idx) {
            return str.substring(pos[idx << 1], pos[idx << 1 | 1]);
        }
    }

    private static class VerbatimPattern extends GlobPattern {

        VerbatimPattern(String value) {
            super(value);
        }

        @Override
        public Match match(String text, int offset) {
            int len = text.length() - offset;
            if (len != parts[0].length()) {
                return null;
            }
            if (!parts[0].regionMatches(0, text, offset, len)) {
                return null;
            }
            return new Match(parts[0], new int[0]);
        }
    }

    private static class WildcardPattern extends GlobPattern {

        @Override
        public Match match(String text, int offset) {
            int len = text.length();
            if (len <= offset) {
                return new Match(text, new int[] { 0, 0 });
            }
            return new Match(text, new int[] { offset, len });
        }

        @Override
        public String toString() {
            return "*";
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy