Class |
Line # |
Actions |
|||
---|---|---|---|---|---|
Skip | 18 | 60 | 37 |
1 | // | |
2 | // This software is now distributed according to | |
3 | // the Lesser Gnu Public License. Please see | |
4 | // http://www.gnu.org/copyleft/lesser.txt for | |
5 | // the details. | |
6 | // -- Happy Computing! | |
7 | // | |
8 | package com.stevesoft.pat; | |
9 | ||
10 | /** | |
11 | * This class is used internally to search ahead for some optimized Regex | |
12 | * objects. It searches within a String for occrences of a given String -- like | |
13 | * a more flexible version of String.indexOf. | |
14 | * | |
15 | * @see com.stevesoft.pat.Skip2 | |
16 | * @see com.stevesoft.pat.SkipBMH | |
17 | */ | |
18 | public class Skip | |
19 | { | |
20 | 0 | static int mkmask(int c) |
21 | { | |
22 | 0 | char x = (char) c; |
23 | 0 | return ~(CaseMgr.toUpperCase(x) | CaseMgr.toLowerCase(x) |
24 | | CaseMgr.toTitleCase(x)); | |
25 | } | |
26 | ||
27 | String src; | |
28 | ||
29 | int c, mask; | |
30 | ||
31 | int offset; | |
32 | ||
33 | boolean ign, m1; | |
34 | ||
35 | /** | |
36 | * Examine a Regex to determine what String it will attempt to skip to when | |
37 | * searching for patterns. Return -1 if we aren't doing this. | |
38 | */ | |
39 | 0 | public static String string(Regex r) |
40 | { | |
41 | 0 | return r.skipper == null ? null : r.skipper.src; |
42 | } | |
43 | ||
44 | /** | |
45 | * Determine the offset of the String within the pattern that we are skipping | |
46 | * to. Return -1 if we aren't doing this. | |
47 | */ | |
48 | 0 | public static int offset(Regex r) |
49 | { | |
50 | 0 | return r.skipper == null ? -1 : r.skipper.offset; |
51 | } | |
52 | ||
53 | /** | |
54 | * Initialize, give it a String to search for, tell it whether or not to | |
55 | * ignoreCase, and what the offset is of the String within the String to be | |
56 | * searched. | |
57 | */ | |
58 | 45 | public Skip(String s, boolean ign, int o) |
59 | { | |
60 | 45 | src = s; |
61 | 45 | c = s.charAt(0); |
62 | 45 | if (ign) |
63 | { | |
64 | 0 | mask = mkmask(c); |
65 | } | |
66 | else | |
67 | { | |
68 | 45 | mask = 0; |
69 | } | |
70 | 45 | offset = o; |
71 | 45 | this.ign = ign; |
72 | 45 | m1 = (s.length() == 1); |
73 | } | |
74 | ||
75 | /** The same as find(s,0,s.length()) */ | |
76 | 0 | public final int find(StringLike s) |
77 | { | |
78 | 0 | return find(s, 0, s.length()); |
79 | } | |
80 | ||
81 | 127535 | static final int min(int a, int b) |
82 | { | |
83 | 127535 | return a < b ? a : b; |
84 | } | |
85 | ||
86 | /** | |
87 | * Searches a given region of text beginning at position start and ending at | |
88 | * position end for the skip object. | |
89 | */ | |
90 | 0 | public int find(StringLike s, int start, int end) |
91 | { | |
92 | 0 | if (start > end) |
93 | { | |
94 | 0 | return -1; |
95 | } | |
96 | 0 | start += offset; |
97 | 0 | int vend = min(s.length() - 1, end + offset); |
98 | 0 | if (mask != c) |
99 | { | |
100 | 0 | for (int i = start; i <= vend; i++) |
101 | { | |
102 | 0 | if (0 == (s.charAt(i) & mask)) |
103 | { | |
104 | // if(m1||s.regionMatches(ign,i,src,0,src.length()) ) | |
105 | 0 | if (m1 || CaseMgr.regionMatches(s, ign, i, src, 0, src.length())) |
106 | { | |
107 | 0 | return i - offset; |
108 | } | |
109 | } | |
110 | } | |
111 | } | |
112 | else | |
113 | { | |
114 | 0 | for (int i = start; i <= vend; i++) |
115 | { | |
116 | 0 | if (c == s.charAt(i)) |
117 | { | |
118 | // if(m1||s.regionMatches(ign,i,src,0,src.length()) ) | |
119 | 0 | if (m1 || CaseMgr.regionMatches(s, ign, i, src, 0, src.length())) |
120 | { | |
121 | 0 | return i - offset; |
122 | } | |
123 | } | |
124 | } | |
125 | } | |
126 | 0 | return -1; |
127 | } | |
128 | ||
129 | 318 | static Skip findSkip(Regex r) |
130 | { | |
131 | 318 | return findSkip(r.thePattern, r.ignoreCase, !r.dontMatchInQuotes); |
132 | } | |
133 | ||
134 | // look for things that can be skipped | |
135 | 543 | static Skip findSkip(Pattern p, boolean ignoreCase, boolean trnc) |
136 | { | |
137 | 543 | StringBuffer sb = new StringBuffer(); |
138 | 543 | Skip subsk = null; |
139 | 543 | int offset = 0; |
140 | 543 | int skipc = -1, skipoff = 0; |
141 | 588 | for (; p != null; p = p.next) |
142 | { | |
143 | 588 | if (p instanceof oneChar) |
144 | { | |
145 | 45 | skipc = ((oneChar) p).c; |
146 | 45 | skipoff = offset; |
147 | } | |
148 | 588 | if (p instanceof oneChar && p.next instanceof oneChar) |
149 | { | |
150 | 45 | Pattern psav = p; |
151 | 45 | sb.append(((oneChar) p).c); |
152 | 90 | while (p.next instanceof oneChar) |
153 | { | |
154 | 45 | sb.append(((oneChar) p.next).c); |
155 | 45 | p = p.next; |
156 | } | |
157 | 45 | String st = sb.toString(); |
158 | 45 | Skip sk = null; |
159 | 45 | if (st.length() > 2) |
160 | { | |
161 | 0 | sk = new SkipBMH(st, ignoreCase, offset); |
162 | } | |
163 | else | |
164 | { | |
165 | 45 | sk = new Skip2(st, ignoreCase, offset); |
166 | } | |
167 | 45 | if (trnc && st.length() > 2) |
168 | { // chop out a whole string... | |
169 | 0 | psav.next = new Skipped(st.substring(1)); |
170 | 0 | psav.next.next = p.next; |
171 | 0 | psav.next.parent = p.parent; |
172 | } | |
173 | 45 | return sk; |
174 | } | |
175 | ? | else if (p instanceof Or && ((Or) p).v.size() == 1 |
176 | && !((Or) p).leftForm().equals("(?!") | |
177 | && null != (subsk = findSkip( | |
178 | (Pattern) ((Or) p).v.elementAt(0), ignoreCase, trnc))) | |
179 | { | |
180 | 0 | subsk.offset += offset; |
181 | 0 | return subsk; |
182 | } | |
183 | 543 | else if (p.minChars().equals(p.maxChars())) |
184 | { | |
185 | 45 | offset += p.minChars().intValue(); |
186 | } | |
187 | else | |
188 | { | |
189 | 498 | return skipc < 0 ? null |
190 | : new Skip("" + (char) skipc, ignoreCase, skipoff); | |
191 | } | |
192 | } | |
193 | 0 | return null; |
194 | } | |
195 | } |