Changeset 1169 in josm for trunk/src/org/openstreetmap/josm/actions/search/SearchCompiler.java
- Timestamp:
- 2008-12-23T15:07:05+01:00 (17 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/actions/search/SearchCompiler.java
r1168 r1169 20 20 public class SearchCompiler { 21 21 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 }29 30 abstract public static class Match {31 abstract public boolean match(OsmPrimitive osm);32 }33 34 private static class Always extends Match {35 @Override public boolean match(OsmPrimitive osm) {36 return true;37 }38 }39 40 private static class Not extends Match {41 private final Match match;42 public Not(Match match) {this.match = match;}43 @Override public boolean match(OsmPrimitive osm) {44 return !match.match(osm);45 }46 @Override public String toString() {return "!"+match;}47 }48 49 private static class And extends Match {50 private Match lhs;51 private Match rhs;52 public And(Match lhs, Match rhs) {this.lhs = lhs; this.rhs = rhs;}53 @Override public boolean match(OsmPrimitive osm) {54 return lhs.match(osm) && rhs.match(osm);55 }56 @Override public String toString() {return lhs+" && "+rhs;}57 }58 59 private static class Or extends Match {60 private Match lhs;61 private Match rhs;62 public Or(Match lhs, Match rhs) {this.lhs = lhs; this.rhs = rhs;}63 @Override public boolean match(OsmPrimitive osm) {64 return lhs.match(osm) || rhs.match(osm);65 }66 @Override public String toString() {return lhs+" || "+rhs;}67 }68 69 private static class Id extends Match {70 private long id;71 public Id(long id) {this.id = id;}72 @Override public boolean match(OsmPrimitive osm) {73 return osm.id == id;74 }75 @Override public String toString() {return "id="+id;}76 }77 78 private class KeyValue extends Match {79 private String key;80 private String value;81 public KeyValue(String key, String value) {this.key = key; this.value = value; }82 @Override public boolean match(OsmPrimitive osm) {83 String value = null;84 if (key.equals("timestamp"))85 value = osm.getTimeStr();86 else87 value = osm.get(key);88 if (value == null)89 return false;90 String v1 = caseSensitive ? value : value.toLowerCase();91 String v2 = caseSensitive ? this.value : this.value.toLowerCase();92 // is not Java 1.593 //v1 = java.text.Normalizer.normalize(v1, java.text.Normalizer.Form.NFC);94 //v2 = java.text.Normalizer.normalize(v2, java.text.Normalizer.Form.NFC);95 return v1.indexOf(v2) != -1;96 }97 @Override public String toString() {return key+"="+value;}98 }99 100 private class Any extends Match {101 private String s;102 public Any(String s) {this.s = s;}103 @Override public boolean match(OsmPrimitive osm) {104 if (osm.keys == null)105 return s.equals("");106 String search = caseSensitive ? s : s.toLowerCase();107 // is not Java 1.5108 //search = java.text.Normalizer.normalize(search, java.text.Normalizer.Form.NFC);109 for (Entry<String, String> e : osm.keys.entrySet()) {110 String key = caseSensitive ? e.getKey() : e.getKey().toLowerCase();111 String value = caseSensitive ? e.getValue() : e.getValue().toLowerCase();112 // is not Java 1.5113 //value = java.text.Normalizer.normalize(value, java.text.Normalizer.Form.NFC);114 if (key.indexOf(search) != -1 || value.indexOf(search) != -1)115 return true;116 }117 if (osm.user != null) {118 String name = osm.user.name;119 // is not Java 1.5120 //String name = java.text.Normalizer.normalize(name, java.text.Normalizer.Form.NFC);121 if (!caseSensitive)122 name = name.toLowerCase();123 if (name.indexOf(search) != -1)124 return true;125 }126 return false;127 }128 @Override public String toString() {return s;}129 }130 131 private static class ExactType extends Match {132 private String type;133 public ExactType(String type) {this.type = type;}134 @Override public boolean match(OsmPrimitive osm) {135 if (osm instanceof Node)136 return type.equals("node");137 if (osm instanceof Way)138 return type.equals("way");139 if (osm instanceof Relation)140 return type.equals("relation");141 throw new IllegalStateException("unknown class "+osm.getClass());142 }143 @Override public String toString() {return "type="+type;}144 }145 146 private static class UserMatch extends Match {147 private User user;148 public UserMatch(String user) { this.user = User.get(user); }149 @Override public boolean match(OsmPrimitive osm) {150 return osm.user == user;151 }152 @Override public String toString() { return "user=" + user.name; }153 }154 155 private static class NodeCount extends Match {156 private int count;157 public NodeCount(int count) {this.count = count;}158 @Override public boolean match(OsmPrimitive osm) {159 return osm instanceof Way && ((Way) osm).nodes.size() == count;160 }161 @Override public String toString() {return "nodes="+count;}162 }163 164 private static class Modified extends Match {165 @Override public boolean match(OsmPrimitive osm) {166 return osm.modified || osm.id == 0;167 }168 @Override public String toString() {return "modified";}169 }170 171 private static class Selected extends Match {172 @Override public boolean match(OsmPrimitive osm) {173 return osm.selected;174 }175 @Override public String toString() {return "selected";}176 }177 178 private static class Incomplete extends Match {179 @Override public boolean match(OsmPrimitive osm) {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 } 29 30 abstract public static class Match { 31 abstract public boolean match(OsmPrimitive osm); 32 } 33 34 private static class Always extends Match { 35 @Override public boolean match(OsmPrimitive osm) { 36 return true; 37 } 38 } 39 40 private static class Not extends Match { 41 private final Match match; 42 public Not(Match match) {this.match = match;} 43 @Override public boolean match(OsmPrimitive osm) { 44 return !match.match(osm); 45 } 46 @Override public String toString() {return "!"+match;} 47 } 48 49 private static class And extends Match { 50 private Match lhs; 51 private Match rhs; 52 public And(Match lhs, Match rhs) {this.lhs = lhs; this.rhs = rhs;} 53 @Override public boolean match(OsmPrimitive osm) { 54 return lhs.match(osm) && rhs.match(osm); 55 } 56 @Override public String toString() {return lhs+" && "+rhs;} 57 } 58 59 private static class Or extends Match { 60 private Match lhs; 61 private Match rhs; 62 public Or(Match lhs, Match rhs) {this.lhs = lhs; this.rhs = rhs;} 63 @Override public boolean match(OsmPrimitive osm) { 64 return lhs.match(osm) || rhs.match(osm); 65 } 66 @Override public String toString() {return lhs+" || "+rhs;} 67 } 68 69 private static class Id extends Match { 70 private long id; 71 public Id(long id) {this.id = id;} 72 @Override public boolean match(OsmPrimitive osm) { 73 return osm.id == id; 74 } 75 @Override public String toString() {return "id="+id;} 76 } 77 78 private class KeyValue extends Match { 79 private String key; 80 private String value; 81 public KeyValue(String key, String value) {this.key = key; this.value = value; } 82 @Override public boolean match(OsmPrimitive osm) { 83 String value = null; 84 if (key.equals("timestamp")) 85 value = osm.getTimeStr(); 86 else 87 value = osm.get(key); 88 if (value == null) 89 return false; 90 String v1 = caseSensitive ? value : value.toLowerCase(); 91 String v2 = caseSensitive ? this.value : this.value.toLowerCase(); 92 // is not Java 1.5 93 //v1 = java.text.Normalizer.normalize(v1, java.text.Normalizer.Form.NFC); 94 //v2 = java.text.Normalizer.normalize(v2, java.text.Normalizer.Form.NFC); 95 return v1.indexOf(v2) != -1; 96 } 97 @Override public String toString() {return key+"="+value;} 98 } 99 100 private class Any extends Match { 101 private String s; 102 public Any(String s) {this.s = s;} 103 @Override public boolean match(OsmPrimitive osm) { 104 if (osm.keys == null) 105 return s.equals(""); 106 String search = caseSensitive ? s : s.toLowerCase(); 107 // is not Java 1.5 108 //search = java.text.Normalizer.normalize(search, java.text.Normalizer.Form.NFC); 109 for (Entry<String, String> e : osm.keys.entrySet()) { 110 String key = caseSensitive ? e.getKey() : e.getKey().toLowerCase(); 111 String value = caseSensitive ? e.getValue() : e.getValue().toLowerCase(); 112 // is not Java 1.5 113 //value = java.text.Normalizer.normalize(value, java.text.Normalizer.Form.NFC); 114 if (key.indexOf(search) != -1 || value.indexOf(search) != -1) 115 return true; 116 } 117 if (osm.user != null) { 118 String name = osm.user.name; 119 // is not Java 1.5 120 //String name = java.text.Normalizer.normalize(name, java.text.Normalizer.Form.NFC); 121 if (!caseSensitive) 122 name = name.toLowerCase(); 123 if (name.indexOf(search) != -1) 124 return true; 125 } 126 return false; 127 } 128 @Override public String toString() {return s;} 129 } 130 131 private static class ExactType extends Match { 132 private String type; 133 public ExactType(String type) {this.type = type;} 134 @Override public boolean match(OsmPrimitive osm) { 135 if (osm instanceof Node) 136 return type.equals("node"); 137 if (osm instanceof Way) 138 return type.equals("way"); 139 if (osm instanceof Relation) 140 return type.equals("relation"); 141 throw new IllegalStateException("unknown class "+osm.getClass()); 142 } 143 @Override public String toString() {return "type="+type;} 144 } 145 146 private static class UserMatch extends Match { 147 private User user; 148 public UserMatch(String user) { this.user = User.get(user); } 149 @Override public boolean match(OsmPrimitive osm) { 150 return osm.user == user; 151 } 152 @Override public String toString() { return "user=" + user.name; } 153 } 154 155 private static class NodeCount extends Match { 156 private int count; 157 public NodeCount(int count) {this.count = count;} 158 @Override public boolean match(OsmPrimitive osm) { 159 return osm instanceof Way && ((Way) osm).nodes.size() == count; 160 } 161 @Override public String toString() {return "nodes="+count;} 162 } 163 164 private static class Modified extends Match { 165 @Override public boolean match(OsmPrimitive osm) { 166 return osm.modified || osm.id == 0; 167 } 168 @Override public String toString() {return "modified";} 169 } 170 171 private static class Selected extends Match { 172 @Override public boolean match(OsmPrimitive osm) { 173 return osm.selected; 174 } 175 @Override public String toString() {return "selected";} 176 } 177 178 private static class Incomplete extends Match { 179 @Override public boolean match(OsmPrimitive osm) { 180 180 return osm.incomplete; 181 }182 @Override public String toString() {return "incomplete";}183 }184 185 public static class ParseError extends Exception {186 public ParseError(String msg) {187 super(msg);188 }189 }190 191 public static Match compile(String searchStr, boolean caseSensitive)192 throws ParseError {193 return new SearchCompiler(caseSensitive,194 new PushbackTokenizer(195 new PushbackReader(new StringReader(searchStr))))196 .parse();197 }198 199 public Match parse() throws ParseError {200 Match m = parseJuxta();201 if (!tokenizer.readIfEqual(null)) {202 throw new ParseError("Unexpected token: " + tokenizer.nextToken());203 }204 return m;205 }206 207 private Match parseJuxta() throws ParseError {208 Match juxta = new Always();209 210 Match m;211 while ((m = parseOr()) != null) {212 juxta = new And(m, juxta);213 }214 215 return juxta;216 }217 218 private Match parseOr() throws ParseError {219 Match a = parseNot();220 if (tokenizer.readIfEqual("|")) {221 Match b = parseNot();222 if (a == null || b == null) {223 throw new ParseError(tr("Missing arguments for or."));224 }225 return new Or(a, b);226 }227 return a;228 }229 230 private Match parseNot() throws ParseError {231 if (tokenizer.readIfEqual("-")) {232 Match m = parseParens();233 if (m == null) {234 throw new ParseError(tr("Missing argument for not."));235 }236 return new Not(m);237 }238 return parseParens();239 }240 241 private Match parseParens() throws ParseError {242 if (tokenizer.readIfEqual("(")) {243 Match m = parseJuxta();244 if (!tokenizer.readIfEqual(")")) {245 throw new ParseError(tr("Expected closing parenthesis."));246 }247 return m;248 }249 return parsePat();250 }251 252 private Match parsePat() {253 String tok = tokenizer.readText();254 255 if (tokenizer.readIfEqual(":")) {256 String tok2 = tokenizer.readText();257 if (tok == null) tok = "";258 if (tok2 == null) tok2 = "";259 return parseKV(tok, tok2);260 }261 262 if (tok == null) {263 return null;264 } else if (tok.equals("modified")) {265 return new Modified();266 } else if (tok.equals("incomplete")) {267 return new Incomplete();268 } else if (tok.equals("selected")) {269 return new Selected();270 } else {271 return new Any(tok);272 }273 }274 275 private Match parseKV(String key, String value) {276 if (key.equals("type")) {277 return new ExactType(value);278 } else if (key.equals("user")) {279 return new UserMatch(value);280 } else if (key.equals("nodes")) {281 return new NodeCount(Integer.parseInt(value));282 } else if (key.equals("id")) {283 try {284 return new Id(Long.parseLong(value));285 } catch (NumberFormatException x) {286 return new Id(0);287 }288 } else {289 return new KeyValue(key, value);290 }291 }181 } 182 @Override public String toString() {return "incomplete";} 183 } 184 185 public static class ParseError extends Exception { 186 public ParseError(String msg) { 187 super(msg); 188 } 189 } 190 191 public static Match compile(String searchStr, boolean caseSensitive) 192 throws ParseError { 193 return new SearchCompiler(caseSensitive, 194 new PushbackTokenizer( 195 new PushbackReader(new StringReader(searchStr)))) 196 .parse(); 197 } 198 199 public Match parse() throws ParseError { 200 Match m = parseJuxta(); 201 if (!tokenizer.readIfEqual(null)) { 202 throw new ParseError("Unexpected token: " + tokenizer.nextToken()); 203 } 204 return m; 205 } 206 207 private Match parseJuxta() throws ParseError { 208 Match juxta = new Always(); 209 210 Match m; 211 while ((m = parseOr()) != null) { 212 juxta = new And(m, juxta); 213 } 214 215 return juxta; 216 } 217 218 private Match parseOr() throws ParseError { 219 Match a = parseNot(); 220 if (tokenizer.readIfEqual("|")) { 221 Match b = parseNot(); 222 if (a == null || b == null) { 223 throw new ParseError(tr("Missing arguments for or.")); 224 } 225 return new Or(a, b); 226 } 227 return a; 228 } 229 230 private Match parseNot() throws ParseError { 231 if (tokenizer.readIfEqual("-")) { 232 Match m = parseParens(); 233 if (m == null) { 234 throw new ParseError(tr("Missing argument for not.")); 235 } 236 return new Not(m); 237 } 238 return parseParens(); 239 } 240 241 private Match parseParens() throws ParseError { 242 if (tokenizer.readIfEqual("(")) { 243 Match m = parseJuxta(); 244 if (!tokenizer.readIfEqual(")")) { 245 throw new ParseError(tr("Expected closing parenthesis.")); 246 } 247 return m; 248 } 249 return parsePat(); 250 } 251 252 private Match parsePat() { 253 String tok = tokenizer.readText(); 254 255 if (tokenizer.readIfEqual(":")) { 256 String tok2 = tokenizer.readText(); 257 if (tok == null) tok = ""; 258 if (tok2 == null) tok2 = ""; 259 return parseKV(tok, tok2); 260 } 261 262 if (tok == null) { 263 return null; 264 } else if (tok.equals("modified")) { 265 return new Modified(); 266 } else if (tok.equals("incomplete")) { 267 return new Incomplete(); 268 } else if (tok.equals("selected")) { 269 return new Selected(); 270 } else { 271 return new Any(tok); 272 } 273 } 274 275 private Match parseKV(String key, String value) { 276 if (key.equals("type")) { 277 return new ExactType(value); 278 } else if (key.equals("user")) { 279 return new UserMatch(value); 280 } else if (key.equals("nodes")) { 281 return new NodeCount(Integer.parseInt(value)); 282 } else if (key.equals("id")) { 283 try { 284 return new Id(Long.parseLong(value)); 285 } catch (NumberFormatException x) { 286 return new Id(0); 287 } 288 } else { 289 return new KeyValue(key, value); 290 } 291 } 292 292 }
Note:
See TracChangeset
for help on using the changeset viewer.
