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
019import org.springframework.lang.Nullable;
020
021/**
022 * Utility methods for simple pattern matching, in particular for
023 * Spring's typical "xxx*", "*xxx" and "*xxx*" pattern styles.
024 *
025 * @author Juergen Hoeller
026 * @since 2.0
027 */
028public abstract class PatternMatchUtils {
029
030        /**
031         * Match a String against the given pattern, supporting the following simple
032         * pattern styles: "xxx*", "*xxx", "*xxx*" and "xxx*yyy" matches (with an
033         * arbitrary number of pattern parts), as well as direct equality.
034         * @param pattern the pattern to match against
035         * @param str the String to match
036         * @return whether the String matches the given pattern
037         */
038        public static boolean simpleMatch(@Nullable String pattern, @Nullable String str) {
039                if (pattern == null || str == null) {
040                        return false;
041                }
042
043                int firstIndex = pattern.indexOf('*');
044                if (firstIndex == -1) {
045                        return pattern.equals(str);
046                }
047
048                if (firstIndex == 0) {
049                        if (pattern.length() == 1) {
050                                return true;
051                        }
052                        int nextIndex = pattern.indexOf('*', 1);
053                        if (nextIndex == -1) {
054                                return str.endsWith(pattern.substring(1));
055                        }
056                        String part = pattern.substring(1, nextIndex);
057                        if (part.isEmpty()) {
058                                return simpleMatch(pattern.substring(nextIndex), str);
059                        }
060                        int partIndex = str.indexOf(part);
061                        while (partIndex != -1) {
062                                if (simpleMatch(pattern.substring(nextIndex), str.substring(partIndex + part.length()))) {
063                                        return true;
064                                }
065                                partIndex = str.indexOf(part, partIndex + 1);
066                        }
067                        return false;
068                }
069
070                return (str.length() >= firstIndex &&
071                                pattern.substring(0, firstIndex).equals(str.substring(0, firstIndex)) &&
072                                simpleMatch(pattern.substring(firstIndex), str.substring(firstIndex)));
073        }
074
075        /**
076         * Match a String against the given patterns, supporting the following simple
077         * pattern styles: "xxx*", "*xxx", "*xxx*" and "xxx*yyy" matches (with an
078         * arbitrary number of pattern parts), as well as direct equality.
079         * @param patterns the patterns to match against
080         * @param str the String to match
081         * @return whether the String matches any of the given patterns
082         */
083        public static boolean simpleMatch(@Nullable String[] patterns, String str) {
084                if (patterns != null) {
085                        for (String pattern : patterns) {
086                                if (simpleMatch(pattern, str)) {
087                                        return true;
088                                }
089                        }
090                }
091                return false;
092        }
093
094}