2 // This software is now distributed according to
\r
3 // the Lesser Gnu Public License. Please see
\r
4 // http://www.gnu.org/copyleft/lesser.txt for
\r
6 // -- Happy Computing!
\r
8 package com.stevesoft.pat;
\r
10 /** This class is used internally to search ahead for some
\r
11 optimized Regex objects. It searches within a String
\r
12 for occrences of a given String -- like a more flexible
\r
13 version of String.indexOf.
\r
14 @see com.stevesoft.pat.Skip2
\r
15 @see com.stevesoft.pat.SkipBMH
\r
19 static int mkmask(int c)
\r
22 return~ (CaseMgr.toUpperCase(x) |
\r
23 CaseMgr.toLowerCase(x) |
\r
24 CaseMgr.toTitleCase(x));
\r
31 /** Examine a Regex to determine what String it will
\r
32 attempt to skip to when searching for patterns.
\r
33 Return -1 if we aren't doing this. */
\r
34 public static String string(Regex r)
\r
36 return r.skipper == null ? null : r.skipper.src;
\r
39 /** Determine the offset of the String within the pattern
\r
40 that we are skipping to. Return -1 if we aren't doing
\r
42 public static int offset(Regex r)
\r
44 return r.skipper == null ? -1 : r.skipper.offset;
\r
47 /** Initialize, give it a String to search for, tell it
\r
48 whether or not to ignoreCase, and what the offset is
\r
49 of the String within the String to be searched. */
\r
50 public Skip(String s, boolean ign, int o)
\r
64 m1 = (s.length() == 1);
\r
67 /** The same as find(s,0,s.length()) */
\r
68 public final int find(StringLike s)
\r
70 return find(s, 0, s.length());
\r
73 static final int min(int a, int b)
\r
75 return a < b ? a : b;
\r
78 /** Searches a given region of text beginning at position start
\r
79 and ending at position end for the skip object. */
\r
80 public int find(StringLike s, int start, int end)
\r
87 int vend = min(s.length() - 1, end + offset);
\r
90 for (int i = start; i <= vend; i++)
\r
92 if (0 == (s.charAt(i) & mask))
\r
94 //if(m1||s.regionMatches(ign,i,src,0,src.length()) )
\r
95 if (m1 || CaseMgr.regionMatches(s, ign, i, src, 0, src.length()))
\r
104 for (int i = start; i <= vend; i++)
\r
106 if (c == s.charAt(i))
\r
108 //if(m1||s.regionMatches(ign,i,src,0,src.length()) )
\r
109 if (m1 || CaseMgr.regionMatches(s, ign, i, src, 0, src.length()))
\r
119 static Skip findSkip(Regex r)
\r
121 return findSkip(r.thePattern, r.ignoreCase, !r.dontMatchInQuotes);
\r
124 // look for things that can be skipped
\r
125 static Skip findSkip(Pattern p, boolean ignoreCase, boolean trnc)
\r
127 StringBuffer sb = new StringBuffer();
\r
130 int skipc = -1, skipoff = 0;
\r
131 for (; p != null; p = p.next)
\r
133 if (p instanceof oneChar)
\r
135 skipc = ( (oneChar) p).c;
\r
138 if (p instanceof oneChar && p.next instanceof oneChar)
\r
141 sb.append( ( (oneChar) p).c);
\r
142 while (p.next instanceof oneChar)
\r
144 sb.append( ( (oneChar) p.next).c);
\r
147 String st = sb.toString();
\r
149 if (st.length() > 2)
\r
151 sk = new SkipBMH(st, ignoreCase, offset);
\r
155 sk = new Skip2(st, ignoreCase, offset);
\r
157 if (trnc && st.length() > 2)
\r
158 { // chop out a whole string...
\r
159 psav.next = new Skipped(st.substring(1));
\r
160 psav.next.next = p.next;
\r
161 psav.next.parent = p.parent;
\r
165 else if (p instanceof Or && ( (Or) p).v.size() == 1
\r
166 && ! ( (Or) p).leftForm().equals("(?!")
\r
167 && null != (subsk =
\r
168 findSkip( (Pattern) ( (Or) p).v.elementAt(0),
\r
169 ignoreCase, trnc)))
\r
171 subsk.offset += offset;
\r
174 else if (p.minChars().equals(p.maxChars()))
\r
176 offset += p.minChars().intValue();
\r
180 return skipc < 0 ? null :
\r
181 new Skip("" + (char) skipc, ignoreCase, skipoff);
\r