Mercurial > hg > Members > kono > jpf-core
comparison src/main/gov/nasa/jpf/util/StringSetMatcher.java @ 3:fdc263e5806b
added inverse matching in StringSetMatcher. Since this is not easy to do in regexes, it's at the next hight level in StringSetMatcher
added a optional CG accessor interface (geChoice(i), getAllChoices(), getProcessedChoices() getUnprocessedChoices()) that can be used from listeners and peers to enumerate/analyse choice sets. Note that not all CGs have to support this as there is no requirement that CGs actually use pre-computed choice sets. The low level accessor is getChoice(i), ChoiceGeneratorBase provides generic (not very efficient) set accessor implementations. Note that ChoiceGeneratorBase.getChoice() has to be overridden in subclasses in order to support choice enumeration, the default impl is just there so that we don't break subclass compilation
author | Peter Mehlitz <Peter.C.Mehlitz@nasa.gov> |
---|---|
date | Tue, 03 Feb 2015 08:49:33 -0800 |
parents | 61d41facf527 |
children |
comparison
equal
deleted
inserted
replaced
2:b920e6b1be83 | 3:fdc263e5806b |
---|---|
20 import java.util.regex.Matcher; | 20 import java.util.regex.Matcher; |
21 import java.util.regex.Pattern; | 21 import java.util.regex.Pattern; |
22 | 22 |
23 /** | 23 /** |
24 * simple utility that can be used to check for string matches in | 24 * simple utility that can be used to check for string matches in |
25 * sets with '*' wildcards, e.g. to check for class name lists like | 25 * sets with '*' wildcards, e.g. to check for class name lists such as |
26 * | 26 * |
27 * vm.halt_on_throw=java.lang.reflect.*:my.own.Exception | 27 * vm.halt_on_throw=java.lang.reflect.*:my.own.Exception |
28 * | 28 * |
29 * Only meta chars in patterns are '*', i.e. '.' is a regular char to match | 29 * Only meta chars in patterns are '*' and '!', i.e. '.' is a regular char to match |
30 * A '!' prefix inverts the match | |
30 */ | 31 */ |
31 public class StringSetMatcher { | 32 public class StringSetMatcher { |
32 | 33 |
34 public static final char WILDCARD = '*'; | |
35 public static final char INVERTED = '!'; | |
36 | |
33 boolean hasAnyPattern; // do we have a universal '*' pattern? | 37 boolean hasAnyPattern; // do we have a universal '*' pattern? |
34 | 38 |
35 Pattern[] pattern; | 39 Pattern[] pattern; |
36 Matcher[] matcher; | 40 Matcher[] matcher; |
41 boolean[] inverted; | |
37 | 42 |
38 /** | 43 /** |
39 * convenience method for matcher pairs containing of explicit excludes and | 44 * convenience method for matcher pairs containing of explicit excludes and |
40 * includes | 45 * includes |
41 */ | 46 */ |
65 | 70 |
66 public StringSetMatcher (String... set){ | 71 public StringSetMatcher (String... set){ |
67 int n = set.length; | 72 int n = set.length; |
68 pattern = new Pattern[n]; | 73 pattern = new Pattern[n]; |
69 matcher = new Matcher[n]; | 74 matcher = new Matcher[n]; |
75 inverted = new boolean[n]; | |
70 | 76 |
71 for (int i=0; i<n; i++){ | 77 for (int i=0; i<n; i++){ |
72 String s = set[i]; | 78 String s = set[i]; |
73 | 79 |
74 if (s.equals("*")) { | 80 if (s.equals("*")) { |
77 | 83 |
78 } else { | 84 } else { |
79 Pattern p = createPattern(s); | 85 Pattern p = createPattern(s); |
80 pattern[i] = p; | 86 pattern[i] = p; |
81 matcher[i] = p.matcher(""); // gets reset upon use | 87 matcher[i] = p.matcher(""); // gets reset upon use |
88 inverted[i] = isInverted(s); | |
82 } | 89 } |
83 } | 90 } |
84 } | 91 } |
85 | 92 |
86 @Override | 93 @Override |
87 public String toString() { | 94 public String toString() { |
88 int n=0; | 95 int n=0; |
89 StringBuilder sb = new StringBuilder(64); | 96 StringBuilder sb = new StringBuilder(64); |
90 sb.append("StringSetMatcher [regex_patterns="); | 97 sb.append("StringSetMatcher {patterns="); |
91 | 98 |
92 if (hasAnyPattern) { | 99 if (hasAnyPattern) { |
93 sb.append(".*"); | 100 sb.append(".*"); |
94 n++; | 101 n++; |
95 } | 102 } |
97 for (int i=0; i<pattern.length; i++) { | 104 for (int i=0; i<pattern.length; i++) { |
98 if (pattern[i] != null) { | 105 if (pattern[i] != null) { |
99 if (n++>0) { | 106 if (n++>0) { |
100 sb.append(','); | 107 sb.append(','); |
101 } | 108 } |
109 if (inverted[i]){ | |
110 sb.append(INVERTED); | |
111 } | |
102 sb.append(pattern[i]); | 112 sb.append(pattern[i]); |
103 } | 113 } |
104 } | 114 } |
105 sb.append(']'); | 115 sb.append('}'); |
106 return sb.toString(); | 116 return sb.toString(); |
107 } | 117 } |
108 | 118 |
109 public void addPattern (String s){ | 119 public void addPattern (String s){ |
110 | 120 |
111 if (s.equals("*")) { // no need to compile | 121 if (s.equals("*")) { // no need to compile |
122 // note that this doesn't include the - pointless - "!*", which would match nothing | |
112 hasAnyPattern = true; | 123 hasAnyPattern = true; |
113 | 124 |
114 } else { | 125 } else { |
115 int n = pattern.length; | 126 int n = pattern.length; |
116 | 127 |
120 | 131 |
121 Matcher[] mNew = new Matcher[pNew.length]; | 132 Matcher[] mNew = new Matcher[pNew.length]; |
122 System.arraycopy(matcher, 0, mNew, 0, n); | 133 System.arraycopy(matcher, 0, mNew, 0, n); |
123 mNew[n] = pNew[n].matcher(""); | 134 mNew[n] = pNew[n].matcher(""); |
124 | 135 |
136 boolean[] iNew = new boolean[pNew.length]; | |
137 System.arraycopy( inverted, 0, iNew, 0, n); | |
138 iNew[n] = isInverted(s); | |
139 | |
125 pattern = pNew; | 140 pattern = pNew; |
126 matcher = mNew; | 141 matcher = mNew; |
127 } | 142 inverted = iNew; |
128 } | 143 } |
129 | 144 } |
130 Pattern createPattern (String s){ | 145 |
146 public static boolean isInverted (String s){ | |
147 return (!s.isEmpty() && s.charAt(0) == INVERTED); | |
148 } | |
149 | |
150 protected Pattern createPattern (String s){ | |
131 Pattern p; | 151 Pattern p; |
132 | 152 int j = 0; |
153 int len = s.length(); | |
154 | |
155 // inversion is better done outside of regex | |
156 if ((len > 0) && s.charAt(0) == INVERTED){ | |
157 j++; // skip INVERTED char | |
158 } | |
159 | |
133 StringBuilder sb = new StringBuilder(); | 160 StringBuilder sb = new StringBuilder(); |
134 | 161 |
135 int len = s.length(); | 162 for (; j<len; j++){ |
136 for (int j=0; j<len; j++){ | |
137 char c = s.charAt(j); | 163 char c = s.charAt(j); |
138 switch (c){ | 164 switch (c){ |
139 case '.' : sb.append("\\."); break; | 165 case '.' : sb.append("\\."); break; |
140 case '$' : sb.append("\\$"); break; | 166 case '$' : sb.append("\\$"); break; |
141 case '[' : sb.append("\\["); break; | 167 case '[' : sb.append("\\["); break; |
163 | 189 |
164 for (int i=0; i<matcher.length; i++){ | 190 for (int i=0; i<matcher.length; i++){ |
165 Matcher m = matcher[i]; | 191 Matcher m = matcher[i]; |
166 m.reset(s); | 192 m.reset(s); |
167 | 193 |
168 if (m.matches()){ | 194 if (m.matches() != inverted[i]){ |
169 return true; | 195 return true; |
170 } | 196 } |
171 } | 197 } |
172 } | 198 } |
173 | 199 |
177 /** | 203 /** |
178 * does 's' match ALL of our patterns | 204 * does 's' match ALL of our patterns |
179 */ | 205 */ |
180 public boolean matchesAll (String s){ | 206 public boolean matchesAll (String s){ |
181 if (s != null) { | 207 if (s != null) { |
182 if (hasAnyPattern && pattern.length == 1) { | 208 if (hasAnyPattern && pattern.length == 1) { // there might be other patterns |
183 return true; // no need to check | 209 return true; // no need to check |
184 } | 210 } |
185 | 211 |
186 for (int i=0; i<pattern.length; i++){ | 212 for (int i=0; i<pattern.length; i++){ |
187 Pattern p = pattern[i]; | 213 Pattern p = pattern[i]; |
188 Matcher m = matcher[i]; | 214 if (p != null){ |
189 m.reset(s); | 215 Matcher m = matcher[i]; |
190 | 216 m.reset(s); |
191 if (!m.matches()){ | 217 |
192 return false; | 218 if (m.matches() == inverted[i]){ |
219 return false; | |
220 } | |
221 } else { | |
222 if (inverted[i]){ | |
223 return false; | |
224 } | |
193 } | 225 } |
194 } | 226 } |
195 | 227 |
196 return true; | 228 return true; |
197 | 229 |