diff --git a/libs/common/src/main/java/org/opensearch/common/Glob.java b/libs/common/src/main/java/org/opensearch/common/Glob.java index daf045dd49e3a..07245d02ee12b 100644 --- a/libs/common/src/main/java/org/opensearch/common/Glob.java +++ b/libs/common/src/main/java/org/opensearch/common/Glob.java @@ -39,47 +39,50 @@ */ public class Glob { + private Glob() {} /** - * Match a String against the given pattern, supporting the following simple - * pattern styles: "xxx*", "*xxx", "*xxx*" and "xxx*yyy" matches (with an - * arbitrary number of pattern parts), as well as direct equality. + * Match a String against the given pattern, supporting the following simple pattern styles: "xxx*", "*xxx", "*xxx*" + * and "xxx*yyy" matches (with an arbitrary number of pattern parts), as well as direct equality. * * @param pattern the pattern to match against - * @param str the String to match + * @param str the String to match * @return whether the String matches the given pattern */ public static boolean globMatch(String pattern, String str) { + if (pattern == null || str == null) { return false; } - int firstIndex = pattern.indexOf('*'); - if (firstIndex == -1) { - return pattern.equals(str); - } - if (firstIndex == 0) { - if (pattern.length() == 1) { - return true; - } - int nextIndex = pattern.indexOf('*', firstIndex + 1); - if (nextIndex == -1) { - return str.endsWith(pattern.substring(1)); - } else if (nextIndex == 1) { - // Double wildcard "**" - skipping the first "*" - return globMatch(pattern.substring(1), str); - } - String part = pattern.substring(1, nextIndex); - int partIndex = str.indexOf(part); - while (partIndex != -1) { - if (globMatch(pattern.substring(nextIndex), str.substring(partIndex + part.length()))) { - return true; - } - partIndex = str.indexOf(part, partIndex + 1); + + int stringIndex=0; + int patternIndex = 0; + int wildcardIndex = -1; + + while (stringIndex < str.length()) { + // pattern and string match + if (patternIndex < pattern.length() && str.charAt(stringIndex) == pattern.charAt(patternIndex)) { + stringIndex++; + patternIndex++; + } else if (patternIndex < pattern.length() && pattern.charAt(patternIndex) == '*') { + // wildcard found + wildcardIndex = patternIndex; + patternIndex++; + } else if (wildcardIndex != -1) { + // last pattern pointer was a wildcard + patternIndex = wildcardIndex + 1; + stringIndex++; + } else { + // characters do not match + return false; } - return false; } - return (str.length() >= firstIndex - && pattern.substring(0, firstIndex).equals(str.substring(0, firstIndex)) - && globMatch(pattern.substring(firstIndex), str.substring(firstIndex))); + + while (patternIndex < pattern.length() && pattern.charAt(patternIndex) == '*') { + patternIndex++; + } + + return patternIndex == pattern.length(); } + } diff --git a/libs/common/src/test/java/org/opensearch/common/GlobTests.java b/libs/common/src/test/java/org/opensearch/common/GlobTests.java new file mode 100644 index 0000000000000..2950c5d30b866 --- /dev/null +++ b/libs/common/src/test/java/org/opensearch/common/GlobTests.java @@ -0,0 +1,84 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.common; + +import org.opensearch.test.OpenSearchTestCase; + +public class GlobTests extends OpenSearchTestCase { + + + public void testGlobMatchNoWildcard() { + assertTrue(Glob.globMatch("test", "test")); + assertFalse(Glob.globMatch("test", "testing")); + } + + + public void testGlobMatchWildcardAtBeginning() { + assertTrue(Glob.globMatch("*test", "thisisatest")); + assertFalse(Glob.globMatch("*test", "thisisatesting")); + } + + + public void testGlobMatchWildcardAtEnd() { + assertTrue(Glob.globMatch("test*", "testthisisa")); + assertFalse(Glob.globMatch("test*", "atestthisis")); + } + + + public void testGlobMatchWildcardAtMiddle() { + assertTrue(Glob.globMatch("test*ing", "testthisisaing")); + assertFalse(Glob.globMatch("test*ing", "testthisisa")); + } + + + public void testGlobMatchMultipleWildcards() { + assertTrue(Glob.globMatch("*test*", "thisisatesting")); + assertFalse(Glob.globMatch("*test*", "thisisatesing")); + assertTrue(Glob.globMatch("*test*test", "thisisatestingtest")); + assertFalse(Glob.globMatch("*test*test", "thisisatesting")); + } + + public void testGlobMatchMultipleCharactersWithSingleWildcard() { + assertTrue(Glob.globMatch("a*b", "acb")); + assertTrue(Glob.globMatch("a*b", "aab")); + assertTrue(Glob.globMatch("a*b", "aaab")); + assertFalse(Glob.globMatch("a*b", "ac")); + } + + public void testGlobMatchWildcardWithEmptyString() { + assertTrue(Glob.globMatch("*", "")); + assertTrue(Glob.globMatch("a*", "a")); + assertFalse(Glob.globMatch("a*", "")); + } + + public void testGlobMatchMultipleWildcardsWithMultipleCharacters() { + assertTrue(Glob.globMatch("a*b*c", "abc")); + assertTrue(Glob.globMatch("a*b*c", "axxxbxbc")); + assertTrue(Glob.globMatch("a*b*c", "aabc")); + assertTrue(Glob.globMatch("a*b*c", "abac")); + assertFalse(Glob.globMatch("a*b*c", "abca")); + assertFalse(Glob.globMatch("a*b*c", "ac")); + } + + + public void testGlobMatchNullPattern() { + assertFalse(Glob.globMatch(null, "test")); + } + + + public void testGlobMatchNullString() { + assertFalse(Glob.globMatch("test", null)); + } + + + public void testGlobMatchNullPatternAndString() { + assertFalse(Glob.globMatch(null, null)); + } +} +