001/*
002 * Copyright 2002-2019 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.util;
018
019/**
020 * Utility methods for simple pattern matching, in particular for
021 * Spring's typical "xxx*", "*xxx" and "*xxx*" pattern styles.
022 *
023 * @author Juergen Hoeller
024 * @since 2.0
025 */
026public abstract class PatternMatchUtils {
027
028        /**
029         * Match a String against the given pattern, supporting the following simple
030         * pattern styles: "xxx*", "*xxx", "*xxx*" and "xxx*yyy" matches (with an
031         * arbitrary number of pattern parts), as well as direct equality.
032         * @param pattern the pattern to match against
033         * @param str the String to match
034         * @return whether the String matches the given pattern
035         */
036        public static boolean simpleMatch(String pattern, String str) {
037                if (pattern == null || str == null) {
038                        return false;
039                }
040
041                int firstIndex = pattern.indexOf('*');
042                if (firstIndex == -1) {
043                        return pattern.equals(str);
044                }
045
046                if (firstIndex == 0) {
047                        if (pattern.length() == 1) {
048                                return true;
049                        }
050                        int nextIndex = pattern.indexOf('*', 1);
051                        if (nextIndex == -1) {
052                                return str.endsWith(pattern.substring(1));
053                        }
054                        String part = pattern.substring(1, nextIndex);
055                        if (part.isEmpty()) {
056                                return simpleMatch(pattern.substring(nextIndex), str);
057                        }
058                        int partIndex = str.indexOf(part);
059                        while (partIndex != -1) {
060                                if (simpleMatch(pattern.substring(nextIndex), str.substring(partIndex + part.length()))) {
061                                        return true;
062                                }
063                                partIndex = str.indexOf(part, partIndex + 1);
064                        }
065                        return false;
066                }
067
068                return (str.length() >= firstIndex &&
069                                pattern.substring(0, firstIndex).equals(str.substring(0, firstIndex)) &&
070                                simpleMatch(pattern.substring(firstIndex), str.substring(firstIndex)));
071        }
072
073        /**
074         * Match a String against the given patterns, supporting the following simple
075         * pattern styles: "xxx*", "*xxx", "*xxx*" and "xxx*yyy" matches (with an
076         * arbitrary number of pattern parts), as well as direct equality.
077         * @param patterns the patterns to match against
078         * @param str the String to match
079         * @return whether the String matches any of the given patterns
080         */
081        public static boolean simpleMatch(String[] patterns, String str) {
082                if (patterns != null) {
083                        for (String pattern : patterns) {
084                                if (simpleMatch(pattern, str)) {
085                                        return true;
086                                }
087                        }
088                }
089                return false;
090        }
091
092}