@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 Matcher rewrite(Function<Matcher, Matcher> f) { return f.apply(new IndexOfMatcher(pattern, next.rewrite(f))); }
@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 Matcher rewrite(Function<Matcher, Matcher> f) { return f.apply(new IndexOfMatcher(pattern, next.rewrite(f))); }
@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)); }
@Test public void combineCharSeqAfterIndexOf() { Matcher input = new IndexOfMatcher("ab", new CharSeqMatcher("cd")); Matcher expected = new IndexOfMatcher("abcd", TrueMatcher.INSTANCE); Assertions.assertEquals(expected, Optimizer.combineCharSeqAfterIndexOf(input)); }
@Test public void optimizeOrSimple() { PatternMatcher actual = PatternMatcher.compile("^abc|def|ghi"); PatternMatcher expected = OrMatcher.create( new StartsWithMatcher("abc"), new IndexOfMatcher("def", TrueMatcher.INSTANCE), new IndexOfMatcher("ghi", TrueMatcher.INSTANCE) ); Assertions.assertEquals(expected, actual); }
@Test public void optimizeEndsWith() { PatternMatcher actual = PatternMatcher.compile(".*foo$"); PatternMatcher expected = new IndexOfMatcher("foo", EndMatcher.INSTANCE); Assertions.assertEquals(expected, actual); }
@Test public void optimizeOrFalse() { PatternMatcher actual = PatternMatcher.compile("abc|$foo|$bar"); PatternMatcher expected = new IndexOfMatcher("abc", TrueMatcher.INSTANCE); Assertions.assertEquals(expected, actual); }
@Test public void optimizeOrIndexOf() { PatternMatcher actual = PatternMatcher.compile("^.*abc.*|.*def.*|.*ghi*."); PatternMatcher expected = OrMatcher.create( new IndexOfMatcher("abc", TrueMatcher.INSTANCE), new IndexOfMatcher("def", TrueMatcher.INSTANCE), new IndexOfMatcher( "gh", new ZeroOrMoreMatcher(new CharSeqMatcher("i"), AnyMatcher.INSTANCE) ) ); Assertions.assertEquals(expected, actual); }
/** * 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; }
/** * 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; }
/** * If a char sequence is preceded by a repeated any match, then replace with an * IndexOfMatcher. The index of operation seems to be optimized by the JDK and is * much faster. Example: {@code ".*foo" => indexOf("foo")}. */ static Matcher convertRepeatedAnyCharSeqToIndexOf(Matcher matcher) { if (matcher instanceof ZeroOrMoreMatcher) { ZeroOrMoreMatcher zm1 = matcher.as(); Matcher prefix = PatternUtils.getPrefix(zm1.next()); if (zm1.repeated() instanceof AnyMatcher && prefix instanceof CharSeqMatcher) { String pattern = prefix.<CharSeqMatcher>as().pattern(); Matcher suffix = PatternUtils.getSuffix(zm1.next()); return new IndexOfMatcher(pattern, suffix); } } return matcher; }
@Test public void optimizeEndsWithPattern() { PatternMatcher actual = PatternMatcher.compile(".*foo.bar$"); PatternMatcher expected = new IndexOfMatcher( "foo", SeqMatcher.create( AnyMatcher.INSTANCE, new CharSeqMatcher("bar"), EndMatcher.INSTANCE ) ); Assertions.assertEquals(expected, actual); }
@Test public void optimizeNegativeLookaheadOr() { PatternMatcher actual = PatternMatcher.compile("^^abc.def(?!.*(1000|1500))"); PatternMatcher expected = SeqMatcher.create( new StartsWithMatcher("abc"), AnyMatcher.INSTANCE, new CharSeqMatcher("def"), new NegativeLookaheadMatcher(new IndexOfMatcher( "1", OrMatcher.create(new CharSeqMatcher("000"), new CharSeqMatcher("500")) )) ); Assertions.assertEquals(expected, actual); } }