Browse Source

Add ignoreCase variants to PatternMatchUtils

See gh-34801
pull/35405/head
rstoyanchev 8 months ago
parent
commit
5c5cf73e11
  1. 61
      spring-core/src/main/java/org/springframework/util/PatternMatchUtils.java
  2. 21
      spring-core/src/test/java/org/springframework/util/PatternMatchUtilsTests.java

61
spring-core/src/main/java/org/springframework/util/PatternMatchUtils.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2023 the original author or authors. * Copyright 2002-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -37,13 +37,24 @@ public abstract class PatternMatchUtils {
* @return whether the String matches the given pattern * @return whether the String matches the given pattern
*/ */
public static boolean simpleMatch(@Nullable String pattern, @Nullable String str) { public static boolean simpleMatch(@Nullable String pattern, @Nullable String str) {
return simpleMatch(pattern, str, false);
}
/**
* Variant of {@link #simpleMatch(String, String)} that ignores upper/lower case.
*/
public static boolean simpleMatchIgnoreCase(@Nullable String pattern, @Nullable String str) {
return simpleMatch(pattern, str, true);
}
private static boolean simpleMatch(@Nullable String pattern, @Nullable String str, boolean ignoreCase) {
if (pattern == null || str == null) { if (pattern == null || str == null) {
return false; return false;
} }
int firstIndex = pattern.indexOf('*'); int firstIndex = pattern.indexOf('*');
if (firstIndex == -1) { if (firstIndex == -1) {
return pattern.equals(str); return (ignoreCase ? pattern.equalsIgnoreCase(str) : pattern.equals(str));
} }
if (firstIndex == 0) { if (firstIndex == 0) {
@ -52,25 +63,43 @@ public abstract class PatternMatchUtils {
} }
int nextIndex = pattern.indexOf('*', 1); int nextIndex = pattern.indexOf('*', 1);
if (nextIndex == -1) { if (nextIndex == -1) {
return str.endsWith(pattern.substring(1)); String part = pattern.substring(1);
return (ignoreCase ? StringUtils.endsWithIgnoreCase(str, part) : str.endsWith(part));
} }
String part = pattern.substring(1, nextIndex); String part = pattern.substring(1, nextIndex);
if (part.isEmpty()) { if (part.isEmpty()) {
return simpleMatch(pattern.substring(nextIndex), str); return simpleMatch(pattern.substring(nextIndex), str, ignoreCase);
} }
int partIndex = str.indexOf(part); int partIndex = indexOf(str, part, 0, ignoreCase);
while (partIndex != -1) { while (partIndex != -1) {
if (simpleMatch(pattern.substring(nextIndex), str.substring(partIndex + part.length()))) { if (simpleMatch(pattern.substring(nextIndex), str.substring(partIndex + part.length()), ignoreCase)) {
return true; return true;
} }
partIndex = str.indexOf(part, partIndex + 1); partIndex = indexOf(str, part, partIndex + 1, ignoreCase);
} }
return false; return false;
} }
return (str.length() >= firstIndex && return (str.length() >= firstIndex &&
pattern.startsWith(str.substring(0, firstIndex)) && checkStartsWith(pattern, str, firstIndex, ignoreCase) &&
simpleMatch(pattern.substring(firstIndex), str.substring(firstIndex))); simpleMatch(pattern.substring(firstIndex), str.substring(firstIndex), ignoreCase));
}
private static boolean checkStartsWith(String pattern, String str, int index, boolean ignoreCase) {
String part = str.substring(0, index);
return (ignoreCase ? StringUtils.startsWithIgnoreCase(pattern, part) : pattern.startsWith(part));
}
private static int indexOf(String str, String otherStr, int startIndex, boolean ignoreCase) {
if (!ignoreCase) {
return str.indexOf(otherStr, startIndex);
}
for (int i = startIndex; i <= (str.length() - otherStr.length()); i++) {
if (str.regionMatches(true, i, otherStr, 0, otherStr.length())) {
return i;
}
}
return -1;
} }
/** /**
@ -94,4 +123,18 @@ public abstract class PatternMatchUtils {
return false; return false;
} }
/**
* Variant of {@link #simpleMatch(String[], String)} that ignores upper/lower case.
*/
public static boolean simpleMatchIgnoreCase(@Nullable String[] patterns, @Nullable String str) {
if (patterns != null) {
for (String pattern : patterns) {
if (simpleMatch(pattern, str, true)) {
return true;
}
}
}
return false;
}
} }

21
spring-core/src/test/java/org/springframework/util/PatternMatchUtilsTests.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2024 the original author or authors. * Copyright 2002-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -53,18 +53,22 @@ class PatternMatchUtilsTests {
assertMatches(new String[] { null, "" }, ""); assertMatches(new String[] { null, "" }, "");
assertMatches(new String[] { null, "123" }, "123"); assertMatches(new String[] { null, "123" }, "123");
assertMatches(new String[] { null, "*" }, "123"); assertMatches(new String[] { null, "*" }, "123");
testMixedCaseMatch("abC", "Abc");
} }
@Test @Test
void startsWith() { void startsWith() {
assertMatches("get*", "getMe"); assertMatches("get*", "getMe");
assertDoesNotMatch("get*", "setMe"); assertDoesNotMatch("get*", "setMe");
testMixedCaseMatch("geT*", "GetMe");
} }
@Test @Test
void endsWith() { void endsWith() {
assertMatches("*Test", "getMeTest"); assertMatches("*Test", "getMeTest");
assertDoesNotMatch("*Test", "setMe"); assertDoesNotMatch("*Test", "setMe");
testMixedCaseMatch("*TeSt", "getMeTesT");
} }
@Test @Test
@ -74,6 +78,10 @@ class PatternMatchUtilsTests {
assertMatches("*stuff*", "stuffTest"); assertMatches("*stuff*", "stuffTest");
assertMatches("*stuff*", "getstuff"); assertMatches("*stuff*", "getstuff");
assertMatches("*stuff*", "stuff"); assertMatches("*stuff*", "stuff");
testMixedCaseMatch("*stuff*", "getStuffTest");
testMixedCaseMatch("*stuff*", "StuffTest");
testMixedCaseMatch("*stuff*", "getStuff");
testMixedCaseMatch("*stuff*", "Stuff");
} }
@Test @Test
@ -82,6 +90,8 @@ class PatternMatchUtilsTests {
assertMatches("on*Event", "onEvent"); assertMatches("on*Event", "onEvent");
assertDoesNotMatch("3*3", "3"); assertDoesNotMatch("3*3", "3");
assertMatches("3*3", "33"); assertMatches("3*3", "33");
testMixedCaseMatch("on*Event", "OnMyEvenT");
testMixedCaseMatch("on*Event", "OnEvenT");
} }
@Test @Test
@ -122,18 +132,27 @@ class PatternMatchUtilsTests {
private void assertMatches(String pattern, String str) { private void assertMatches(String pattern, String str) {
assertThat(PatternMatchUtils.simpleMatch(pattern, str)).isTrue(); assertThat(PatternMatchUtils.simpleMatch(pattern, str)).isTrue();
assertThat(PatternMatchUtils.simpleMatchIgnoreCase(pattern, str)).isTrue();
} }
private void assertDoesNotMatch(String pattern, String str) { private void assertDoesNotMatch(String pattern, String str) {
assertThat(PatternMatchUtils.simpleMatch(pattern, str)).isFalse(); assertThat(PatternMatchUtils.simpleMatch(pattern, str)).isFalse();
assertThat(PatternMatchUtils.simpleMatchIgnoreCase(pattern, str)).isFalse();
}
private void testMixedCaseMatch(String pattern, String str) {
assertThat(PatternMatchUtils.simpleMatch(pattern, str)).isFalse();
assertThat(PatternMatchUtils.simpleMatchIgnoreCase(pattern, str)).isTrue();
} }
private void assertMatches(String[] patterns, String str) { private void assertMatches(String[] patterns, String str) {
assertThat(PatternMatchUtils.simpleMatch(patterns, str)).isTrue(); assertThat(PatternMatchUtils.simpleMatch(patterns, str)).isTrue();
assertThat(PatternMatchUtils.simpleMatchIgnoreCase(patterns, str)).isTrue();
} }
private void assertDoesNotMatch(String[] patterns, String str) { private void assertDoesNotMatch(String[] patterns, String str) {
assertThat(PatternMatchUtils.simpleMatch(patterns, str)).isFalse(); assertThat(PatternMatchUtils.simpleMatch(patterns, str)).isFalse();
assertThat(PatternMatchUtils.simpleMatchIgnoreCase(patterns, str)).isFalse();
} }
} }

Loading…
Cancel
Save