/** * 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; }
@Override public int matches(String str, int start, int length) { if (next == TrueMatcher.INSTANCE) { int pos = indexOf(str, start); return pos >= 0 ? pos + pattern.length() : Constants.NO_MATCH; } else if (next == EndMatcher.INSTANCE) { return endsWith(str, start) ? length : Constants.NO_MATCH; } else { final int end = start + length; final int stop = end - next.minLength(); int pos = start; while (pos >= 0 && pos <= stop) { pos = indexOf(str, pos); if (pos >= 0) { int s = pos + pattern.length(); int p = next.matches(str, s, end - s); if (p >= 0) { return p; } ++pos; } } return Constants.NO_MATCH; } }
private boolean endsWith(String str, int offset) { final int remaining = str.length() - offset; final int length = pattern.length(); if (remaining < length) { return false; } return ignoreCase ? endsWithIgnoreCase(str) : str.endsWith(pattern); }
@Override public Matcher rewrite(Function<Matcher, Matcher> f) { return f.apply(new IndexOfMatcher(pattern, next.rewrite(f))); }
private int indexOf(String str, int offset) { return ignoreCase ? indexOfIgnoreCase(str, offset) : str.indexOf(pattern, offset); }
@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); }
private int indexOf(String str, int offset) { return ignoreCase ? indexOfIgnoreCase(str, offset) : str.indexOf(pattern, offset); }
/** * 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; }
@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 public int matches(String str, int start, int length) { if (next == TrueMatcher.INSTANCE) { int pos = indexOf(str, start); return pos >= 0 ? pos + pattern.length() : Constants.NO_MATCH; } else if (next == EndMatcher.INSTANCE) { return endsWith(str, start) ? length : Constants.NO_MATCH; } else { final int end = start + length; final int stop = end - next.minLength(); int pos = start; while (pos >= 0 && pos <= stop) { pos = indexOf(str, pos); if (pos >= 0) { int s = pos + pattern.length(); int p = next.matches(str, s, end - s); if (p >= 0) { return p; } ++pos; } } return Constants.NO_MATCH; } }
private boolean endsWith(String str, int offset) { final int remaining = str.length() - offset; final int length = pattern.length(); if (remaining < length) { return false; } return ignoreCase ? endsWithIgnoreCase(str) : str.endsWith(pattern); }
/** Convert to a matchers that ignores the case. */ static Matcher ignoreCase(Matcher matcher) { if (matcher instanceof CharClassMatcher) { CharClassMatcher m = matcher.as(); return new CharClassMatcher(m.set(), true); } else if (matcher instanceof CharSeqMatcher) { CharSeqMatcher m = matcher.as(); return new CharSeqMatcher(m.pattern(), true); } else if (matcher instanceof IndexOfMatcher) { IndexOfMatcher m = matcher.as(); return new IndexOfMatcher(m.pattern(), m.next(), true); } else if (matcher instanceof StartsWithMatcher) { StartsWithMatcher m = matcher.as(); return new StartsWithMatcher(m.pattern(), true); } else { return matcher; } }
@Override public Matcher rewrite(Function<Matcher, Matcher> f) { return f.apply(new IndexOfMatcher(pattern, next.rewrite(f))); }
/** Convert to a matchers that ignores the case. */ static Matcher ignoreCase(Matcher matcher) { if (matcher instanceof CharClassMatcher) { CharClassMatcher m = matcher.as(); return new CharClassMatcher(m.set(), true); } else if (matcher instanceof CharSeqMatcher) { CharSeqMatcher m = matcher.as(); return new CharSeqMatcher(m.pattern(), true); } else if (matcher instanceof IndexOfMatcher) { IndexOfMatcher m = matcher.as(); return new IndexOfMatcher(m.pattern(), m.next(), true); } else if (matcher instanceof StartsWithMatcher) { StartsWithMatcher m = matcher.as(); return new StartsWithMatcher(m.pattern(), true); } else { return matcher; } }
@Override public Matcher rewriteEnd(Function<Matcher, Matcher> f) { return f.apply(new IndexOfMatcher(pattern, next.rewriteEnd(f))); }
@Override public Matcher rewriteEnd(Function<Matcher, Matcher> f) { return f.apply(new IndexOfMatcher(pattern, next.rewriteEnd(f))); }
@Test public void optimizeOrPrefixPattern() { PatternMatcher actual = PatternMatcher.compile("^abc.*foo$|^abc.*bar$|^abc.*baz$"); PatternMatcher expected = SeqMatcher.create( new StartsWithMatcher("abc"), new OrMatcher( new IndexOfMatcher("foo", EndMatcher.INSTANCE), new IndexOfMatcher("bar", EndMatcher.INSTANCE), new IndexOfMatcher("baz", EndMatcher.INSTANCE) ) ); Assertions.assertEquals(expected, actual); }
@Test public void optimizeIndexOfSeqAny() { PatternMatcher actual = PatternMatcher.compile("^.*abc.*def.*"); PatternMatcher expected = new IndexOfMatcher( "abc", new IndexOfMatcher("def", TrueMatcher.INSTANCE) ); Assertions.assertEquals(expected, actual); }
@Test public void optimizeIndexOfSeq() { PatternMatcher actual = PatternMatcher.compile("^.*abc.*def"); PatternMatcher expected = new IndexOfMatcher( "abc", new IndexOfMatcher("def", TrueMatcher.INSTANCE) ); Assertions.assertEquals(expected, actual); }
@Test public void removeMatchAnyFollowedByIndexOf() { Matcher input = new ZeroOrMoreMatcher( AnyMatcher.INSTANCE, new IndexOfMatcher("foo", TrueMatcher.INSTANCE)); Matcher expected = new IndexOfMatcher("foo", TrueMatcher.INSTANCE); Assertions.assertEquals(expected, Optimizer.removeMatchAnyFollowedByIndexOf(input)); }