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
28 /** Examine a Regex to determine what String it will
\r
29 attempt to skip to when searching for patterns.
\r
30 Return -1 if we aren't doing this. */
\r
31 public static String string(Regex r) {
\r
32 return r.skipper == null ? null : r.skipper.src;
\r
34 /** Determine the offset of the String within the pattern
\r
35 that we are skipping to. Return -1 if we aren't doing
\r
37 public static int offset(Regex r) {
\r
38 return r.skipper == null ? -1 : r.skipper.offset;
\r
40 /** Initialize, give it a String to search for, tell it
\r
41 whether or not to ignoreCase, and what the offset is
\r
42 of the String within the String to be searched. */
\r
43 public Skip(String s,boolean ign,int o) {
\r
51 m1 = (s.length()==1);
\r
53 /** The same as find(s,0,s.length()) */
\r
54 public final int find(StringLike s) {
\r
55 return find(s,0,s.length());
\r
57 static final int min(int a,int b) { return a<b ? a : b; }
\r
58 /** Searches a given region of text beginning at position start
\r
59 and ending at position end for the skip object. */
\r
60 public int find(StringLike s,int start,int end) {
\r
61 if(start > end) return -1;
\r
63 int vend = min(s.length()-1,end+offset);
\r
65 for(int i=start;i<=vend;i++)
\r
66 if(0 == (s.charAt(i) & mask))
\r
67 //if(m1||s.regionMatches(ign,i,src,0,src.length()) )
\r
68 if(m1||CaseMgr.regionMatches(s,ign,i,src,0,src.length()) )
\r
71 for(int i=start;i<=vend;i++)
\r
72 if(c == s.charAt(i))
\r
73 //if(m1||s.regionMatches(ign,i,src,0,src.length()) )
\r
74 if(m1||CaseMgr.regionMatches(s,ign,i,src,0,src.length()) )
\r
79 static Skip findSkip(Regex r) {
\r
80 return findSkip(r.thePattern,r.ignoreCase,!r.dontMatchInQuotes);
\r
82 // look for things that can be skipped
\r
83 static Skip findSkip(Pattern p,boolean ignoreCase,boolean trnc) {
\r
84 StringBuffer sb = new StringBuffer();
\r
87 int skipc = -1,skipoff=0;
\r
88 for(;p != null;p = p.next) {
\r
89 if(p instanceof oneChar) {
\r
90 skipc = ((oneChar)p).c;
\r
93 if(p instanceof oneChar && p.next instanceof oneChar) {
\r
95 sb.append(((oneChar)p).c);
\r
96 while(p.next instanceof oneChar) {
\r
97 sb.append(((oneChar)p.next).c);
\r
100 String st = sb.toString();
\r
103 sk = new SkipBMH(st,ignoreCase,offset);
\r
105 sk = new Skip2(st,ignoreCase,offset);
\r
106 if(trnc && st.length()>2) { // chop out a whole string...
\r
107 psav.next = new Skipped(st.substring(1));
\r
108 psav.next.next = p.next;
\r
109 psav.next.parent = p.parent;
\r
112 } else if(p instanceof Or && ((Or)p).v.size()==1
\r
113 && !((Or)p).leftForm().equals("(?!")
\r
115 findSkip( (Pattern)((Or)p).v.elementAt(0),ignoreCase,trnc) )) {
\r
116 subsk.offset += offset;
\r
118 } else if(p.minChars().equals(p.maxChars())) {
\r
119 offset += p.minChars().intValue();
\r
120 } else return skipc < 0 ? null :
\r
121 new Skip(""+(char)skipc,ignoreCase,skipoff);
\r