// // 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; } }