Index: trunk/src/org/openstreetmap/josm/data/osm/search/PushbackTokenizer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/search/PushbackTokenizer.java	(revision 16259)
+++ trunk/src/org/openstreetmap/josm/data/osm/search/PushbackTokenizer.java	(revision 16260)
@@ -108,4 +108,8 @@
         EQUALS(marktr("<equals>")),
         /**
+         * The tilde sign (~)
+         */
+        TILDE(marktr("<tilde>")),
+        /**
          * A text
          */
@@ -148,5 +152,5 @@
     }
 
-    private static final List<Character> SPECIAL_CHARS = Arrays.asList('"', ':', '(', ')', '|', '^', '=', '?', '<', '>');
+    private static final List<Character> SPECIAL_CHARS = Arrays.asList('"', ':', '(', ')', '|', '^', '=', '~', '?', '<', '>');
     private static final List<Character> SPECIAL_CHARS_QUOTED = Arrays.asList('"');
 
@@ -200,4 +204,7 @@
             getChar();
             return Token.EQUALS;
+        case '~':
+            getChar();
+            return Token.TILDE;
         case '<':
             getChar();
Index: trunk/src/org/openstreetmap/josm/data/osm/search/SearchCompiler.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/search/SearchCompiler.java	(revision 16259)
+++ trunk/src/org/openstreetmap/josm/data/osm/search/SearchCompiler.java	(revision 16260)
@@ -2119,4 +2119,6 @@
             if (tokenizer.readIfEqual(Token.EQUALS)) {
                 return new ExactKeyValue(regexSearch, key, tokenizer.readTextOrNumber());
+            } else if (tokenizer.readIfEqual(Token.TILDE)) {
+                return new ExactKeyValue(true, key, tokenizer.readTextOrNumber());
             } else if (tokenizer.readIfEqual(Token.LESS_THAN)) {
                 return new ValueComparison(key, tokenizer.readTextOrNumber(), -1);
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/SearchDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/SearchDialog.java	(revision 16259)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/SearchDialog.java	(revision 16260)
@@ -294,4 +294,5 @@
                 .addKeyword("<i>key</i>", null, tr("matches if ''key'' exists"))
                 .addKeyword("<i>key</i>=<i>value</i>", null, tr("''key'' with exactly ''value''"))
+                .addKeyword("<i>key</i>~<i>regexp</i>", null, tr("value of ''key'' matching the regular expression ''regexp''"))
                 .addKeyword("<i>key</i>=*", null, tr("''key'' with any value"))
                 .addKeyword("<i>key</i>=", null, tr("''key'' with empty value"))
Index: trunk/test/unit/org/openstreetmap/josm/data/osm/search/SearchCompilerTest.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/data/osm/search/SearchCompilerTest.java	(revision 16259)
+++ trunk/test/unit/org/openstreetmap/josm/data/osm/search/SearchCompilerTest.java	(revision 16260)
@@ -142,4 +142,19 @@
 
     /**
+     * Search by regular expression: key~value.
+     * @throws SearchParseError if an error has been encountered while compiling
+     */
+    @Test
+    public void testRegexp() throws SearchParseError {
+        final SearchCompiler.Match c = SearchCompiler.compile("foo~[Bb]a[rz]");
+        assertFalse(c.match(newPrimitive("foobar", "true")));
+        assertFalse(c.match(newPrimitive("foo", "foo")));
+        assertTrue(c.match(newPrimitive("foo", "bar")));
+        assertTrue(c.match(newPrimitive("foo", "baz")));
+        assertTrue(c.match(newPrimitive("foo", "Baz")));
+        assertEquals("foo=[Bb]a[rz]", c.toString());
+    }
+
+    /**
      * Search by comparison.
      * @throws SearchParseError if an error has been encountered while compiling
