Index: src/org/openstreetmap/josm/actions/search/SearchCompiler.java
===================================================================
--- src/org/openstreetmap/josm/actions/search/SearchCompiler.java	(revision 1627)
+++ src/org/openstreetmap/josm/actions/search/SearchCompiler.java	(working copy)
@@ -153,7 +153,129 @@
         }
         @Override public String toString() {return key+"="+value;}
     }
+    
+    private static class ExactKeyValue extends Match {
+        
+        private enum Mode {
+            ANY, ANY_KEY, ANY_VALUE, EXACT, NONE, MISSING_KEY, 
+            ANY_KEY_REGEXP, ANY_VALUE_REGEXP, EXACT_REGEXP, MISSING_KEY_REGEXP;
+        }
+        
+        private final String key;
+        private final String value;
+        private final Pattern keyPattern;
+        private final Pattern valuePattern;
+        private final Mode mode;
+        
+        public ExactKeyValue(boolean regexp, String key, String value) throws ParseError {
+            if (key == "") {
+                throw new ParseError("Key cannot be empty when tag operator is used. Sample use: key=value");
+            }            
+            this.key = key;
+            this.value = value;
+            if ("".equals(value) && "*".equals(key)) {
+                mode = Mode.NONE;
+            } else if ("".equals(value)) {
+                if (regexp) {
+                    mode = Mode.MISSING_KEY_REGEXP;
+                } else {
+                    mode = Mode.MISSING_KEY;
+                }
+            } else if ("*".equals(key) && "*".equals(value)) {
+                mode = Mode.ANY;
+            } else if ("*".equals(key)) {
+                if (regexp) {
+                    mode = Mode.ANY_KEY_REGEXP;
+                } else {
+                    mode = Mode.ANY_KEY;
+                }
+            } else if ("*".equals(value)) {
+                if (regexp) {
+                    mode = Mode.ANY_VALUE_REGEXP;
+                } else {
+                    mode = Mode.ANY_VALUE;
+                }
+            } else {
+                if (regexp) {
+                    mode = Mode.EXACT_REGEXP;
+                } else {
+                    mode = Mode.EXACT;
+                }
+            }
+            
+            if (regexp && key.length() > 0 && !key.equals("*")) {
+                keyPattern = Pattern.compile(key);
+            } else {
+                keyPattern = null;
+            }
+            if (regexp && value.length() > 0 && !value.equals("*")) {
+                valuePattern = Pattern.compile(value);
+            } else {
+                valuePattern = null;
+            }
+        }
 
+        @Override
+        public boolean match(OsmPrimitive osm) throws ParseError {
+            
+            if (osm.keys == null || osm.keys.isEmpty()) {
+                return mode == Mode.NONE;
+            }
+            
+            switch (mode) {
+            case NONE:
+                return false;
+            case MISSING_KEY:
+                return osm.get(key) == null;
+            case ANY:
+                return true;
+            case ANY_VALUE:
+                return osm.get(key) != null;
+            case ANY_KEY:
+                for (String v:osm.keys.values()) {
+                    if (v.equals(value)) {
+                        return true;
+                    }
+                }
+                return false;
+            case EXACT:
+                return value.equals(osm.get(key));
+            case ANY_KEY_REGEXP:
+                for (String v:osm.keys.values()) {
+                    if (valuePattern.matcher(v).matches()) {
+                        return true;
+                    }
+                }
+                return false;
+            case ANY_VALUE_REGEXP:
+            case EXACT_REGEXP:
+                for (Entry<String, String> entry:osm.keys.entrySet()) {
+                    if (keyPattern.matcher(entry.getKey()).matches()) {
+                        if (mode == Mode.ANY_VALUE_REGEXP 
+                                || valuePattern.matcher(entry.getValue()).matches()) {
+                            return true;
+                        }
+                    }
+                }
+                return false;
+            case MISSING_KEY_REGEXP:
+                for (String k:osm.keys.keySet()) {
+                    if (keyPattern.matcher(k).matches()) {
+                        return false;
+                    }
+                }
+                return true;
+            }  
+            throw new AssertionError("Missed state");
+        }
+        
+        @Override
+        public String toString() {
+            return key + '=' + value;
+        }
+        
+    }
+
     private class Any extends Match {
         private String s;
         public Any(String s) {this.s = s;}
@@ -427,6 +549,13 @@
             if (tok2 == null) tok2 = "";
             return parseKV(tok, tok2);
         }
+        
+        if (tokenizer.readIfEqual("=")) {
+            String tok2 = tokenizer.readText();
+            if (tok == null) tok = "";
+            if (tok2 == null) tok2 = "";
+            return new ExactKeyValue(regexSearch, tok, tok2);
+        }
 
         if (tok == null) {
             return null;
@@ -476,7 +605,7 @@
             return new KeyValue(key, value);
         }
     }
-
+    
     private int regexFlags() {
         int searchFlags = 0;
 
Index: src/org/openstreetmap/josm/actions/search/SearchAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/search/SearchAction.java	(revision 1627)
+++ src/org/openstreetmap/josm/actions/search/SearchAction.java	(working copy)
@@ -3,6 +3,7 @@
 
 import static org.openstreetmap.josm.tools.I18n.tr;
 
+import java.awt.Font;
 import java.awt.GridBagLayout;
 import java.awt.event.ActionEvent;
 import java.awt.event.KeyEvent;
@@ -78,10 +79,13 @@
         left.add(regexSearch, GBC.eol());
 
         JPanel right = new JPanel();
-        right.add(new JLabel("<html><ul>"
+        JLabel description = 
+        new JLabel("<html><ul>"
                 + "<li>"+tr("<b>Baker Street</b> - 'Baker' and 'Street' in any key or name.")+"</li>"
                 + "<li>"+tr("<b>\"Baker Street\"</b> - 'Baker Street' in any key or name.")+"</li>"
                 + "<li>"+tr("<b>name:Bak</b> - 'Bak' anywhere in the name.")+"</li>"
+                + "<li>"+tr("<b>type=route</b> - key 'type' with value exactly 'route'.") + "</li>"
+                + "<li>"+tr("<b>type=*</b> - key 'type' with any value. Try also <b>*=value</b>, <b>type=</b>, <b>*=*</b>, <b>*=</b>") + "</li>"
                 + "<li>"+tr("<b>-name:Bak</b> - not 'Bak' in the name.")+"</li>"
                 + "<li>"+tr("<b>foot:</b> - key=foot set to any value.")+"</li>"
                 + "<li>"+tr("<u>Special targets:</u>")+"</li>"
@@ -98,7 +102,9 @@
                 + "<li>"+tr("Use <b>|</b> or <b>OR</b> to combine with logical or")+"</li>"
                 + "<li>"+tr("Use <b>\"</b> to quote operators (e.g. if key contains :)")+"</li>"
                 + "<li>"+tr("Use <b>(</b> and <b>)</b> to group expressions")+"</li>"
-                + "</ul></html>"));
+                + "</ul></html>");
+        description.setFont(description.getFont().deriveFont(Font.PLAIN));
+        right.add(description);
 
         final JPanel p = new JPanel();
         p.add(left);
Index: src/org/openstreetmap/josm/actions/search/PushbackTokenizer.java
===================================================================
--- src/org/openstreetmap/josm/actions/search/PushbackTokenizer.java	(revision 1627)
+++ src/org/openstreetmap/josm/actions/search/PushbackTokenizer.java	(working copy)
@@ -39,14 +39,14 @@
             StringBuilder s;
             switch (c) {
             case ':':
+            case '=':
                 next = search.read();
-                c = (char) next;
-                if (next == -1 || c == ' ' || c == '\t') {
+                if (next == -1 || next == ' ' || next == '\t') {
                     pushBack(" ");
                 } else {
                     search.unread(next);
                 }
-                return ":";
+                return String.valueOf(c);
             case '-':
                 return "-";
             case '(':
@@ -71,7 +71,7 @@
                     return " "+s.toString();
                 }
                 c = (char)next;
-                if (c == ' ' || c == '\t' || c == '"' || c == ':' || c == '(' || c == ')' || c == '|') {
+                if (c == ' ' || c == '\t' || c == '"' || c == ':' || c == '(' || c == ')' || c == '|' || c == '=') {
                     search.unread(next);
                     if (s.toString().equals("OR"))
                         return "|";
