Skip to content

Commit 4420254

Browse files
No file path support in StringUtils#matchesGlob() (#5514)
To match file paths against glob patterns, the `PathUtils#matchesGlob()` should be used.
1 parent 69ee1d6 commit 4420254

1 file changed

Lines changed: 49 additions & 56 deletions

File tree

rewrite-core/src/main/java/org/openrewrite/internal/StringUtils.java

Lines changed: 49 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@
1919
import org.jspecify.annotations.Nullable;
2020

2121
import java.io.ByteArrayOutputStream;
22-
import java.io.File;
2322
import java.io.IOException;
2423
import java.io.InputStream;
2524
import java.nio.charset.Charset;
2625
import java.nio.charset.StandardCharsets;
26+
import java.nio.file.Path;
2727
import java.util.Arrays;
2828
import java.util.function.Predicate;
2929
import java.util.regex.Pattern;
@@ -36,7 +36,6 @@ private StringUtils() {
3636

3737
public static @Nullable String trimIndentPreserveCRLF(@Nullable String text) {
3838
if (text == null) {
39-
//noinspection DataFlowIssue
4039
return null;
4140
}
4241
return trimIndent((text.endsWith("\r\n") ? text.substring(0, text.length() - 2) : text)
@@ -227,7 +226,7 @@ public static String capitalize(String value) {
227226
return value;
228227
}
229228
return Character.toUpperCase(value.charAt(0)) +
230-
value.substring(1);
229+
value.substring(1);
231230
}
232231

233232
public static String uncapitalize(String value) {
@@ -372,58 +371,48 @@ public static String repeat(String s, int count) {
372371
return new String(multiple);
373372
}
374373

375-
public static boolean matchesGlob(@Nullable String value, @Nullable String globPattern) {
376-
if ("*".equals(globPattern)) {
374+
/**
375+
* Checks if a given string matches a specified glob pattern. A glob pattern may include
376+
* special characters such as '*' to represent any sequence of characters and '?' to
377+
* represent any single character.
378+
* <p>
379+
* For file path matching, use {@link org.openrewrite.PathUtils#matchesGlob(Path, String)},
380+
* which properly interprets '*' and '**' wildcards for file paths.
381+
*
382+
* @param str the input string to match against the pattern, can be null
383+
* @param pattern the glob pattern to evaluate, can be null
384+
* @return true if the input string matches the glob pattern, false otherwise
385+
* @see org.openrewrite.PathUtils#matchesGlob(Path, String)
386+
*/
387+
public static boolean matchesGlob(@Nullable String str, @Nullable String pattern) {
388+
if ("*".equals(pattern)) {
377389
return true;
378-
}
379-
if (globPattern == null) {
390+
} else if (pattern == null) {
380391
return false;
381392
}
382-
if (value == null) {
383-
value = "";
384-
}
385393

386-
return matchesGlob(
387-
globPattern.replace(wrongFileSeparatorChar, File.separatorChar),
388-
value.replace(wrongFileSeparatorChar, File.separatorChar),
389-
false
390-
);
391-
}
394+
if (str == null) {
395+
str = "";
396+
}
392397

393-
private static final char wrongFileSeparatorChar = File.separatorChar == '/' ? '\\' : '/';
398+
if (str.isEmpty() && !pattern.isEmpty()) {
399+
return allStars(pattern, 0, pattern.length() - 1);
400+
} else if (pattern.isEmpty()) {
401+
return str.isEmpty();
402+
}
394403

395-
private static boolean matchesGlob(String pattern, String str, boolean caseSensitive) {
396404
int patIdxStart = 0;
397405
int patIdxEnd = pattern.length() - 1;
398406
int strIdxStart = 0;
399407
int strIdxEnd = str.length() - 1;
400408

401-
if (!pattern.contains("*")) {
402-
// No '*'s, so we make a shortcut
403-
if (patIdxEnd != strIdxEnd) {
404-
return false; // Pattern and string do not have the same size
405-
}
406-
for (int i = 0; i <= patIdxEnd; i++) {
407-
char ch = pattern.charAt(i);
408-
if (ch != '?' && different(caseSensitive, ch, str.charAt(i))) {
409-
return false; // Character mismatch
410-
}
411-
}
412-
return true; // String matches against pattern
413-
}
414-
415-
if (patIdxEnd == 0) {
416-
return true; // Pattern contains only '*', which matches anything
417-
}
418-
419409
// Process characters before first star
420410
while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
421411
char ch = pattern.charAt(patIdxStart);
422412
if (ch == '*') {
423413
break;
424414
}
425-
if (ch != '?' &&
426-
different(caseSensitive, ch, str.charAt(strIdxStart))) {
415+
if (ch != '?' && different(ch, str.charAt(strIdxStart))) {
427416
return false; // Character mismatch
428417
}
429418
patIdxStart++;
@@ -444,7 +433,7 @@ private static boolean matchesGlob(String pattern, String str, boolean caseSensi
444433
if (ch == '*') {
445434
break;
446435
}
447-
if (ch != '?' && different(caseSensitive, ch, str.charAt(strIdxEnd))) {
436+
if (ch != '?' && different(ch, str.charAt(strIdxEnd))) {
448437
return false; // Character mismatch
449438
}
450439
patIdxEnd--;
@@ -456,7 +445,7 @@ private static boolean matchesGlob(String pattern, String str, boolean caseSensi
456445
return allStars(pattern, patIdxStart, patIdxEnd);
457446
}
458447

459-
// process pattern between stars. padIdxStart and patIdxEnd point
448+
// Process pattern between stars. patIdxStart and patIdxEnd point
460449
// always to a '*'.
461450
while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
462451
int patIdxTmp = -1;
@@ -475,18 +464,9 @@ private static boolean matchesGlob(String pattern, String str, boolean caseSensi
475464
// strIdxStart & strIdxEnd
476465
int patLength = (patIdxTmp - patIdxStart - 1);
477466
int strLength = (strIdxEnd - strIdxStart + 1);
478-
int foundIdx = -1;
479-
strLoop:
480-
for (int i = 0; i <= strLength - patLength; i++) {
481-
for (int j = 0; j < patLength; j++) {
482-
char ch = pattern.charAt(patIdxStart + j + 1);
483-
if (ch != '?' && different(caseSensitive, ch, str.charAt(strIdxStart + i + j))) {
484-
continue strLoop;
485-
}
486-
}
487-
foundIdx = strIdxStart + i;
488-
break;
489-
}
467+
468+
int foundIdx = findPatternInString(pattern, patIdxStart + 1, patLength,
469+
str, strIdxStart, strLength);
490470

491471
if (foundIdx == -1) {
492472
return false;
@@ -500,6 +480,21 @@ private static boolean matchesGlob(String pattern, String str, boolean caseSensi
500480
return allStars(pattern, patIdxStart, patIdxEnd);
501481
}
502482

483+
private static int findPatternInString(String pattern, int patStart, int patLength,
484+
String str, int strStart, int strLength) {
485+
strLoop:
486+
for (int i = 0; i <= strLength - patLength; i++) {
487+
for (int j = 0; j < patLength; j++) {
488+
char ch = pattern.charAt(patStart + j);
489+
if (ch != '?' && different(ch, str.charAt(strStart + i + j))) {
490+
continue strLoop;
491+
}
492+
}
493+
return strStart + i;
494+
}
495+
return -1;
496+
}
497+
503498
private static boolean allStars(String chars, int start, int end) {
504499
for (int i = start; i <= end; ++i) {
505500
if (chars.charAt(i) != '*') {
@@ -509,10 +504,8 @@ private static boolean allStars(String chars, int start, int end) {
509504
return true;
510505
}
511506

512-
private static boolean different(boolean caseSensitive, char ch, char other) {
513-
return caseSensitive ?
514-
ch != other :
515-
Character.toUpperCase(ch) != Character.toUpperCase(other);
507+
private static boolean different(char ch, char other) {
508+
return Character.toUpperCase(ch) != Character.toUpperCase(other);
516509
}
517510

518511
public static String indent(String text) {

0 commit comments

Comments
 (0)