in jbatch/src/main/java/org/apache/batchee/container/jsl/GlobPatternMatcherImpl.java [49:149]
private boolean recursiveMatch(final String toMatch, final String subpattern) {
final int firstAsterisk = subpattern.indexOf("*");
final int secondAsterisk = subpattern.indexOf("*", firstAsterisk + 1);
final int lastAsterisk = subpattern.lastIndexOf("*");
//
// A) If there are no '*'(s), do a non-wildcard (except for ?) match
//
if (firstAsterisk == -1) {
return matchNoAsterisk(toMatch, subpattern);
}
//
// B) Match off any beginning or end
//
// Match any beginning BEFORE the first asterisk
if (firstAsterisk > 0) {
final String beginPattern = subpattern.substring(0, firstAsterisk);
if (toMatch.length() < beginPattern.length()) {
return false;
}
final String beginToMatch = toMatch.substring(0, firstAsterisk);
if (!matchNoAsterisk(beginToMatch, beginPattern)) {
return false;
}
}
// This will just be a straight copy if 'firstAsterisk' = 0.
// Since we're using recursion, try to be a bit performance-sensitive and not do this until necessary.
String remainingToMatch = toMatch.substring(firstAsterisk);
//Match any end AFTER the first asterisk
if (lastAsterisk < subpattern.length() - 1) {
final String endPattern = subpattern.substring(lastAsterisk + 1);
if (remainingToMatch.length() < endPattern.length()) {
return false;
}
// Give me a substring the size of 'endPattern' at the end
final String endToMatch = remainingToMatch.substring(remainingToMatch.length() - endPattern.length(), remainingToMatch.length());
if (!matchNoAsterisk(endToMatch, endPattern)) {
return false;
}
// Already matched against char at index: 'remainingToMatch.length() - endPattern.length()', so truncate immediately before.
remainingToMatch = remainingToMatch.substring(0, remainingToMatch.length() - endPattern.length());
}
// C) Now I either have:
// 1) *
// 2) *-xxxxx-* (All non-'*' chars in the middle
// 3) *-xy-*-x-* (At least one '*' in the middle)
if (firstAsterisk == lastAsterisk) {
return true;
} else if (secondAsterisk == lastAsterisk) {
final String middlePattern = subpattern.substring(firstAsterisk + 1, lastAsterisk);
if (remainingToMatch.length() < middlePattern.length()) {
return false;
} else {
for (int i = 0; i <= remainingToMatch.length() - middlePattern.length(); i++) {
final String matchCandidate = remainingToMatch.substring(i, i + middlePattern.length());
if (matchNoAsterisk(matchCandidate, middlePattern)) {
return true;
}
}
return false;
}
} else {
//
// Now I have to match against sub-sub-pattern *xxx*xy*. The strategy here is to use recursion.
// 1. Isolate 'xxx' and store as 'patternBetweenAsterisk1and2'
final String patternBetweenAsterisk1and2 = subpattern.substring(firstAsterisk + 1, secondAsterisk);
// 2. Find every place in the string matching 'xxx' and store the remainder as a candidate
final List<String> subMatchCandidates = new ArrayList<String>();
for (int i = 0; i <= remainingToMatch.length() - patternBetweenAsterisk1and2.length(); i++) {
final String matchCandidate = remainingToMatch.substring(i, i + patternBetweenAsterisk1and2.length());
if (matchNoAsterisk(matchCandidate, patternBetweenAsterisk1and2)) {
// Grab the part of the string after the match.
String subMatchCandidate = remainingToMatch.substring(i + patternBetweenAsterisk1and2.length());
subMatchCandidates.add(subMatchCandidate);
}
}
if (subMatchCandidates.size() == 0) {
return false;
}
// 2. Calculate the new pattern to match against.
// For "*xxx*xy*" this would be "*xy*".
// For "*xxx*xy*z*" this would be "*xy*z*"
final String nestedPattern = subpattern.substring(secondAsterisk, lastAsterisk + 1); // We want to include the last asterisk.
// 3. try matching each one
for (final String candidate : subMatchCandidates) {
if (recursiveMatch(candidate, nestedPattern)) {
return true;
}
}
return false;
}
}