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