// // This software is now distributed according to // the Lesser Gnu Public License. Please see // http://www.gnu.org/copyleft/lesser.txt for // the details. // -- Happy Computing! // package com.stevesoft.pat; /** This class is used internally to search ahead for some optimized Regex objects. It searches within a String for occrences of a given String -- like a more flexible version of String.indexOf. @see com.stevesoft.pat.Skip2 @see com.stevesoft.pat.SkipBMH */ public class Skip { static int mkmask(int c) { char x = (char) c; return~ (CaseMgr.toUpperCase(x) | CaseMgr.toLowerCase(x) | CaseMgr.toTitleCase(x)); } String src; int c, mask; int offset; boolean ign, m1; /** Examine a Regex to determine what String it will attempt to skip to when searching for patterns. Return -1 if we aren't doing this. */ public static String string(Regex r) { return r.skipper == null ? null : r.skipper.src; } /** Determine the offset of the String within the pattern that we are skipping to. Return -1 if we aren't doing this. */ public static int offset(Regex r) { return r.skipper == null ? -1 : r.skipper.offset; } /** Initialize, give it a String to search for, tell it whether or not to ignoreCase, and what the offset is of the String within the String to be searched. */ public Skip(String s, boolean ign, int o) { src = s; c = s.charAt(0); if (ign) { mask = mkmask(c); } else { mask = 0; } offset = o; this.ign = ign; m1 = (s.length() == 1); } /** The same as find(s,0,s.length()) */ public final int find(StringLike s) { return find(s, 0, s.length()); } static final int min(int a, int b) { return a < b ? a : b; } /** Searches a given region of text beginning at position start and ending at position end for the skip object. */ public int find(StringLike s, int start, int end) { if (start > end) { return -1; } start += offset; int vend = min(s.length() - 1, end + offset); if (mask != c) { for (int i = start; i <= vend; i++) { if (0 == (s.charAt(i) & mask)) { //if(m1||s.regionMatches(ign,i,src,0,src.length()) ) if (m1 || CaseMgr.regionMatches(s, ign, i, src, 0, src.length())) { return i - offset; } } } } else { for (int i = start; i <= vend; i++) { if (c == s.charAt(i)) { //if(m1||s.regionMatches(ign,i,src,0,src.length()) ) if (m1 || CaseMgr.regionMatches(s, ign, i, src, 0, src.length())) { return i - offset; } } } } return -1; } static Skip findSkip(Regex r) { return findSkip(r.thePattern, r.ignoreCase, !r.dontMatchInQuotes); } // look for things that can be skipped static Skip findSkip(Pattern p, boolean ignoreCase, boolean trnc) { StringBuffer sb = new StringBuffer(); Skip subsk = null; int offset = 0; int skipc = -1, skipoff = 0; for (; p != null; p = p.next) { if (p instanceof oneChar) { skipc = ( (oneChar) p).c; skipoff = offset; } if (p instanceof oneChar && p.next instanceof oneChar) { Pattern psav = p; sb.append( ( (oneChar) p).c); while (p.next instanceof oneChar) { sb.append( ( (oneChar) p.next).c); p = p.next; } String st = sb.toString(); Skip sk = null; if (st.length() > 2) { sk = new SkipBMH(st, ignoreCase, offset); } else { sk = new Skip2(st, ignoreCase, offset); } if (trnc && st.length() > 2) { // chop out a whole string... psav.next = new Skipped(st.substring(1)); psav.next.next = p.next; psav.next.parent = p.parent; } return sk; } else if (p instanceof Or && ( (Or) p).v.size() == 1 && ! ( (Or) p).leftForm().equals("(?!") && null != (subsk = findSkip( (Pattern) ( (Or) p).v.elementAt(0), ignoreCase, trnc))) { subsk.offset += offset; return subsk; } else if (p.minChars().equals(p.maxChars())) { offset += p.minChars().intValue(); } else { return skipc < 0 ? null : new Skip("" + (char) skipc, ignoreCase, skipoff); } } return null; } }