@Override default PatternMatcher ignoreCase() { Matcher m = rewrite(PatternUtils::ignoreCase); return new IgnoreCaseMatcher(m); }
/** * Adjacent any matches can be consolidated, e.g., ({@code ".*(.*foo)" => ".*foo"}). */ static Matcher removeMatchAnyFollowedByIndexOf(Matcher matcher) { if (matcher instanceof ZeroOrMoreMatcher) { ZeroOrMoreMatcher zm = matcher.as(); if (zm.repeated() instanceof AnyMatcher && PatternUtils.getPrefix(zm.next()) instanceof IndexOfMatcher) { return zm.next(); } } return matcher; }
@Override public Matcher mergeNext(Matcher after) { if (after instanceof TrueMatcher) { return this; } Matcher m = (next instanceof TrueMatcher) ? after : SeqMatcher.create(next, after); return new ZeroOrMoreMatcher(repeated, m); }
/** * If a char sequence is adjacent to an index of matcher, then append the sequence to * the pattern of the index of matcher. */ static Matcher combineCharSeqAfterIndexOf(Matcher matcher) { if (matcher instanceof IndexOfMatcher) { IndexOfMatcher m = matcher.as(); Matcher next = PatternUtils.head(m.next()); if (next instanceof CharSeqMatcher) { String pattern = m.pattern() + next.<CharSeqMatcher>as().pattern(); return new IndexOfMatcher(pattern, PatternUtils.tail(m.next())); } } return matcher; }
/** * Zero or more start anchors is the same as not being anchored by the start. */ static Matcher removeRepeatedStart(Matcher matcher) { if (matcher instanceof ZeroOrMoreMatcher) { ZeroOrMoreMatcher zm = matcher.as(); if (zm.repeated() instanceof StartMatcher) { return zm.next(); } } return matcher; }
@Override public Matcher mergeNext(Matcher after) { if (after instanceof TrueMatcher) { return this; } Matcher m = (next instanceof TrueMatcher) ? after : SeqMatcher.create(next, after); return new IndexOfMatcher(pattern, m); }
/** * If a sequence contains an explicit false matcher then the whole sequence will never match * and can be treated as false. */ static Matcher sequenceWithFalseIsFalse(Matcher matcher) { if (matcher instanceof SeqMatcher) { for (Matcher m : matcher.<SeqMatcher>as().matchers()) { if (m instanceof FalseMatcher) { return FalseMatcher.INSTANCE; } } } return matcher; }
/** Create a new instance. */ static Matcher create(Matcher... matchers) { switch (matchers.length) { case 0: return TrueMatcher.INSTANCE; case 1: return matchers[0]; default: return new OrMatcher(matchers); } }
/** * Compile a pattern string and return a matcher that can be used to check if string values * match the pattern. Pattern matchers are can be reused many times and are thread safe. */ static PatternMatcher compile(String pattern) { return PatternUtils.compile(pattern); }
@Override public boolean isEndAnchored() { boolean anchored = true; for (Matcher m : matchers) { anchored &= m.isEndAnchored(); } return anchored; }
/** * Zero or more start anchors is the same as not being anchored by the start. */ static Matcher removeRepeatedStart(Matcher matcher) { if (matcher instanceof ZeroOrMoreMatcher) { ZeroOrMoreMatcher zm = matcher.as(); if (zm.repeated() instanceof StartMatcher) { return zm.next(); } } return matcher; }
/** * Adjacent any matches can be consolidated, e.g., ({@code ".*(.*foo)" => ".*foo"}). */ static Matcher removeMatchAnyFollowedByIndexOf(Matcher matcher) { if (matcher instanceof ZeroOrMoreMatcher) { ZeroOrMoreMatcher zm = matcher.as(); if (zm.repeated() instanceof AnyMatcher && PatternUtils.getPrefix(zm.next()) instanceof IndexOfMatcher) { return zm.next(); } } return matcher; }
@Override public Matcher mergeNext(Matcher after) { if (after instanceof TrueMatcher) { return this; } Matcher m = (next instanceof TrueMatcher) ? after : SeqMatcher.create(next, after); return new ZeroOrMoreMatcher(repeated, m); }
@Override public Matcher mergeNext(Matcher after) { if (after instanceof TrueMatcher) { return this; } Matcher m = (next instanceof TrueMatcher) ? after : SeqMatcher.create(next, after); return new IndexOfMatcher(pattern, m); }
@Override default PatternMatcher ignoreCase() { Matcher m = rewrite(PatternUtils::ignoreCase); return new IgnoreCaseMatcher(m); }
/** * If the match after a repeated pattern is false, then treat the whole match as false. * For example: {@code ".*$." => "$."}. */ static Matcher zeroOrMoreFalse(Matcher matcher) { if (matcher instanceof ZeroOrMoreMatcher) { ZeroOrMoreMatcher zm = matcher.as(); if (zm.repeated() instanceof FalseMatcher || zm.next() instanceof FalseMatcher) { return zm.next(); } } return matcher; }
/** * Remove match any pattern at the end, e.g., ({@code "foo.*$" => "foo"}). */ static Matcher removeTrailingMatchAny(Matcher matcher) { if (matcher instanceof ZeroOrMoreMatcher) { ZeroOrMoreMatcher zm = matcher.as(); boolean atEnd = zm.next() instanceof TrueMatcher || zm.next() instanceof EndMatcher; if (atEnd && zm.repeated() instanceof AnyMatcher) { return TrueMatcher.INSTANCE; } } return matcher; }
/** * Remove match any pattern at the end, e.g., ({@code "foo.*$" => "foo"}). */ static Matcher removeTrailingMatchAny(Matcher matcher) { if (matcher instanceof ZeroOrMoreMatcher) { ZeroOrMoreMatcher zm = matcher.as(); boolean atEnd = zm.next() instanceof TrueMatcher || zm.next() instanceof EndMatcher; if (atEnd && zm.repeated() instanceof AnyMatcher) { return TrueMatcher.INSTANCE; } } return matcher; }
/** * If the match after a repeated pattern is false, then treat the whole match as false. * For example: {@code ".*$." => "$."}. */ static Matcher zeroOrMoreFalse(Matcher matcher) { if (matcher instanceof ZeroOrMoreMatcher) { ZeroOrMoreMatcher zm = matcher.as(); if (zm.repeated() instanceof FalseMatcher || zm.next() instanceof FalseMatcher) { return zm.next(); } } return matcher; }