Changeset 513 in josm for trunk/src/org/openstreetmap
- Timestamp:
- 2008-01-08T15:02:34+01:00 (17 years ago)
- Location:
- trunk/src/org/openstreetmap/josm/actions/search
- Files:
-
- 1 added
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/actions/search/SearchCompiler.java
r343 r513 6 6 import java.io.StringReader; 7 7 import java.util.Map.Entry; 8 import java.util.regex.Pattern; 9 import java.util.regex.Matcher; 8 10 9 11 import org.openstreetmap.josm.data.osm.Node; … … 18 20 public class SearchCompiler { 19 21 20 boolean caseSensitive = false; 22 private boolean caseSensitive = false; 23 private PushbackTokenizer tokenizer; 24 25 public SearchCompiler(boolean caseSensitive, PushbackTokenizer tokenizer) { 26 this.caseSensitive = caseSensitive; 27 this.tokenizer = tokenizer; 28 } 21 29 22 30 abstract public static class Match { … … 71 79 private String key; 72 80 private String value; 73 boolean notValue; 74 public KeyValue(String key, String value, boolean notValue) {this.key = key; this.value = value; this.notValue = notValue;} 81 public KeyValue(String key, String value) {this.key = key; this.value = value; } 75 82 @Override public boolean match(OsmPrimitive osm) { 76 83 String value = null; … … 80 87 value = osm.get(key); 81 88 if (value == null) 82 return notValue;89 return false; 83 90 String v1 = caseSensitive ? value : value.toLowerCase(); 84 91 String v2 = caseSensitive ? this.value : this.value.toLowerCase(); 85 return (v1.indexOf(v2) != -1) != notValue;86 } 87 @Override public String toString() {return key+"="+ (notValue?"!":"")+value;}92 return v1.indexOf(v2) != -1; 93 } 94 @Override public String toString() {return key+"="+value;} 88 95 } 89 96 … … 151 158 152 159 public static Match compile(String searchStr, boolean caseSensitive) { 153 SearchCompiler searchCompiler = new SearchCompiler(); 154 searchCompiler.caseSensitive = caseSensitive; 155 return searchCompiler.parse(new PushbackReader(new StringReader(searchStr))); 156 } 157 158 159 /** 160 * The token returned is <code>null</code> or starts with an identifier character: 161 * - for an '-'. This will be the only character 162 * : for an key. The value is the next token 163 * | for "OR" 164 * ' ' for anything else. 165 * @return The next token in the stream. 166 */ 167 private String nextToken(PushbackReader search) { 168 try { 169 int next; 170 char c = ' '; 171 while (c == ' ' || c == '\t' || c == '\n') { 172 next = search.read(); 173 if (next == -1) 174 return null; 175 c = (char)next; 176 } 177 StringBuilder s; 178 switch (c) { 179 case '-': 180 return "-"; 181 case '"': 182 s = new StringBuilder(" "); 183 for (int nc = search.read(); nc != -1 && nc != '"'; nc = search.read()) 184 s.append((char)nc); 185 int nc = search.read(); 186 if (nc != -1 && (char)nc == ':') 187 return ":"+s.toString(); 188 if (nc != -1) 189 search.unread(nc); 190 return s.toString(); 191 default: 192 s = new StringBuilder(); 193 for (;;) { 194 s.append(c); 195 next = search.read(); 196 if (next == -1) { 197 if (s.toString().equals("OR")) 198 return "|"; 199 return " "+s.toString(); 200 } 201 c = (char)next; 202 if (c == ' ' || c == '\t' || c == ':' || c == '"') { 203 if (c == ':') 204 return ":"+s.toString(); 205 search.unread(next); 206 if (s.toString().equals("OR")) 207 return "|"; 208 return " "+s.toString(); 209 } 210 } 211 } 212 } catch (IOException e) { 213 throw new RuntimeException(e.getMessage(), e); 214 } 215 } 216 217 218 private boolean notKey = false; 219 private boolean notValue = false; 220 private boolean or = false; 221 private String key = null; 222 String token = null; 223 private Match build() { 224 String value = token.substring(1); 225 if (key == null) { 226 Match c = null; 227 if (value.equals("modified")) 228 c = new Modified(); 229 else if (value.equals("incomplete")) 230 c = new Incomplete(); 231 else if (value.equals("selected")) 232 c = new Selected(); 233 else 234 c = new Any(value); 235 return notValue ? new Not(c) : c; 236 } 237 Match c; 238 if (key.equals("type")) 239 c = new ExactType(value); 240 else if (key.equals("property")) { 241 String realKey = "", realValue = value; 242 int eqPos = value.indexOf("="); 243 if (eqPos != -1) { 244 realKey = value.substring(0,eqPos); 245 realValue = value.substring(eqPos+1); 246 } 247 c = new KeyValue(realKey, realValue, notValue); 160 return new SearchCompiler(caseSensitive, 161 new PushbackTokenizer( 162 new PushbackReader(new StringReader(searchStr)))) 163 .parse(); 164 } 165 166 public Match parse() { 167 Match m = parseJuxta(); 168 if (!tokenizer.readIfEqual(null)) { 169 throw new RuntimeException("Unexpected token: " + tokenizer.nextToken()); 170 } 171 return m; 172 } 173 174 private Match parseJuxta() { 175 Match juxta = new Always(); 176 177 Match m; 178 while ((m = parseOr()) != null) { 179 juxta = new And(m, juxta); 180 } 181 182 return juxta; 183 } 184 185 private Match parseOr() { 186 Match a = parseNot(); 187 if (tokenizer.readIfEqual("|")) { 188 Match b = parseNot(); 189 if (a == null || b == null) { 190 throw new RuntimeException("Missing arguments for or."); 191 } 192 return new Or(a, b); 193 } 194 return a; 195 } 196 197 private Match parseNot() { 198 if (tokenizer.readIfEqual("-")) { 199 Match m = parseParens(); 200 if (m == null) { 201 throw new RuntimeException("Missing argument for not."); 202 } 203 return new Not(m); 204 } 205 return parseParens(); 206 } 207 208 private Match parseParens() { 209 if (tokenizer.readIfEqual("(")) { 210 Match m = parseJuxta(); 211 if (!tokenizer.readIfEqual(")")) { 212 throw new RuntimeException("Expected closing paren"); 213 } 214 return m; 215 } 216 return parsePat(); 217 } 218 219 private Match parsePat() { 220 String tok = tokenizer.readText(); 221 222 if (tokenizer.readIfEqual(":")) { 223 String tok2 = tokenizer.readText(); 224 if (tok == null) tok = ""; 225 if (tok2 == null) tok2 = ""; 226 return parseKV(tok, tok2); 227 } 228 229 if (tok == null) { 230 return null; 231 } else if (tok.equals("modified")) { 232 return new Modified(); 233 } else if (tok.equals("incomplete")) { 234 return new Incomplete(); 235 } else if (tok.equals("selected")) { 236 return new Selected(); 237 } else { 238 return new Any(tok); 239 } 240 } 241 242 private Match parseKV(String key, String value) { 243 if (key.equals("type")) { 244 return new ExactType(value); 248 245 } else if (key.equals("id")) { 249 246 try { 250 c =new Id(Long.parseLong(value));247 return new Id(Long.parseLong(value)); 251 248 } catch (NumberFormatException x) { 252 c = new Id(0); 253 } 254 if (notValue) 255 c = new Not(c); 256 } else 257 c = new KeyValue(key, value, notValue); 258 if (notKey) 259 return new Not(c); 260 return c; 261 } 262 263 private Match parse(PushbackReader search) { 264 Match result = null; 265 for (token = nextToken(search); token != null; token = nextToken(search)) { 266 if (token.equals("-")) 267 notValue = true; 268 else if (token.equals("|")) { 269 if (result == null) 270 continue; 271 or = true; 272 notValue = false; 273 } else if (token.startsWith(":")) { 274 if (key == null) { 275 key = token.substring(1); 276 notKey = notValue; 277 notValue = false; 278 } else 279 key += token.substring(1); 280 } else { 281 Match current = build(); 282 if (result == null) 283 result = current; 284 else 285 result = or ? new Or(result, current) : new And(result, current); 286 key = null; 287 notKey = false; 288 notValue = false; 289 or = false; 290 } 291 } 292 // if "key:" was the last search 293 if (key != null) { 294 token = " "; 295 Match current = build(); 296 result = (result == null) ? current : new And(result, current); 297 } 298 return result == null ? new Always() : result; 249 return new Id(0); 250 } 251 } else { 252 return new KeyValue(key, value); 253 } 299 254 } 300 255 }
Note:
See TracChangeset
for help on using the changeset viewer.