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
18 static int mkmask(int c) {
\r
20 return ~( CaseMgr.toUpperCase(x) |
\r
21 CaseMgr.toLowerCase(x) |
\r
22 CaseMgr.toTitleCase(x));
\r
24 static { int x = Regex.BackRefOffset; }
\r
29 /** Examine a Regex to determine what String it will
\r
30 attempt to skip to when searching for patterns.
\r
31 Return -1 if we aren't doing this. */
\r
32 public static String string(Regex r) {
\r
33 return r.skipper == null ? null : r.skipper.src;
\r
35 /** Determine the offset of the String within the pattern
\r
36 that we are skipping to. Return -1 if we aren't doing
\r
38 public static int offset(Regex r) {
\r
39 return r.skipper == null ? -1 : r.skipper.offset;
\r
41 /** Initialize, give it a String to search for, tell it
\r
42 whether or not to ignoreCase, and what the offset is
\r
43 of the String within the String to be searched. */
\r
44 public Skip(String s,boolean ign,int o) {
\r
52 m1 = (s.length()==1);
\r
54 /** The same as find(s,0,s.length()) */
\r
55 public final int find(StringLike s) {
\r
56 return find(s,0,s.length());
\r
58 static final int min(int a,int b) { return a<b ? a : b; }
\r
59 /** Searches a given region of text beginning at position start
\r
60 and ending at position end for the skip object. */
\r
61 public int find(StringLike s,int start,int end) {
\r
62 if(start > end) return -1;
\r
64 int vend = min(s.length()-1,end+offset);
\r
66 for(int i=start;i<=vend;i++)
\r
67 if(0 == (s.charAt(i) & mask))
\r
68 //if(m1||s.regionMatches(ign,i,src,0,src.length()) )
\r
69 if(m1||CaseMgr.regionMatches(s,ign,i,src,0,src.length()) )
\r
72 for(int i=start;i<=vend;i++)
\r
73 if(c == s.charAt(i))
\r
74 //if(m1||s.regionMatches(ign,i,src,0,src.length()) )
\r
75 if(m1||CaseMgr.regionMatches(s,ign,i,src,0,src.length()) )
\r
80 static Skip findSkip(Regex r) {
\r
81 return findSkip(r.thePattern,r.ignoreCase,!r.dontMatchInQuotes);
\r
83 // look for things that can be skipped
\r
84 static Skip findSkip(Pattern p,boolean ignoreCase,boolean trnc) {
\r
85 StringBuffer sb = new StringBuffer();
\r
88 int skipc = -1,skipoff=0;
\r
89 for(;p != null;p = p.next) {
\r
90 if(p instanceof oneChar) {
\r
91 skipc = ((oneChar)p).c;
\r
94 if(p instanceof oneChar && p.next instanceof oneChar) {
\r
96 sb.append(((oneChar)p).c);
\r
97 while(p.next instanceof oneChar) {
\r
98 sb.append(((oneChar)p.next).c);
\r
101 String st = sb.toString();
\r
102 char c0 = st.charAt(0), c1 = st.charAt(1);
\r
105 sk = new SkipBMH(st,ignoreCase,offset);
\r
107 sk = new Skip2(st,ignoreCase,offset);
\r
108 if(trnc && st.length()>2) { // chop out a whole string...
\r
109 psav.next = new Skipped(st.substring(1));
\r
110 psav.next.next = p.next;
\r
111 psav.next.parent = p.parent;
\r
114 } else if(p instanceof Or && ((Or)p).v.size()==1
\r
115 && !((Or)p).leftForm().equals("(?!")
\r
117 findSkip( (Pattern)((Or)p).v.elementAt(0),ignoreCase,trnc) )) {
\r
118 subsk.offset += offset;
\r
120 } else if(p.minChars().equals(p.maxChars())) {
\r
121 offset += p.minChars().intValue();
\r
122 } else return skipc < 0 ? null :
\r
123 new Skip(""+(char)skipc,ignoreCase,skipoff);
\r