Index: /trunk/src/org/openstreetmap/josm/actions/search/PushbackTokenizer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/search/PushbackTokenizer.java	(revision 4345)
+++ /trunk/src/org/openstreetmap/josm/actions/search/PushbackTokenizer.java	(revision 4346)
@@ -40,4 +40,5 @@
     private Long currentRange;
     private int c;
+    private boolean isRange;
 
     public PushbackTokenizer(Reader search) {
@@ -157,4 +158,5 @@
             if ("and".equalsIgnoreCase(currentText))
                 return nextToken();
+            // try parsing number
             try {
                 currentNumber = Long.parseLong(currentText);
@@ -162,14 +164,21 @@
                 currentNumber = null;
             }
+            // if text contains "-", try parsing a range
             int pos = currentText.indexOf('-', 1);
-            if (pos > 0) {
+            isRange = pos > 0;
+            if (isRange) {
                 try {
                     currentNumber = Long.parseLong(currentText.substring(0, pos));
+                } catch (NumberFormatException e) {
+                    currentNumber = null;
+                }
+                try {
                     currentRange = Long.parseLong(currentText.substring(pos + 1));
                 } catch (NumberFormatException e) {
-                    currentNumber = null;
+                    currentRange = null;
+                    }
+                } else {
                     currentRange = null;
                 }
-            }
             return Token.KEY;
         }
@@ -204,11 +213,19 @@
 
     public Range readRange(String errorMessage) throws ParseError {
-        if ((nextToken() == Token.KEY) && (currentNumber != null)) {
-            if (currentRange == null)
+        if (nextToken() != Token.KEY || (currentNumber == null && currentRange == null)) {
+            throw new ParseError(errorMessage);
+        } else if (!isRange && currentNumber != null) {
+            if (currentNumber >= 0) {
                 return new Range(currentNumber, currentNumber);
-            else
-                return new Range(currentNumber, currentRange);
-        } else
+            } else {
+                return new Range(0, Math.abs(currentNumber));
+            }
+        } else if (isRange && currentRange == null) {
+            return new Range(currentNumber, Integer.MAX_VALUE);
+        } else if (currentNumber != null && currentRange != null) {
+            return new Range(currentNumber, currentRange);
+        } else {
             throw new ParseError(errorMessage);
+        }
     }
 
Index: /trunk/src/org/openstreetmap/josm/actions/search/SearchAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/search/SearchAction.java	(revision 4345)
+++ /trunk/src/org/openstreetmap/josm/actions/search/SearchAction.java	(revision 4346)
@@ -195,9 +195,9 @@
                     + "<li>"+tr("<b>version:</b>... - object with given version (0 objects without an assigned version)")+"</li>"
                     + "<li>"+tr("<b>changeset:</b>... - object with given changeset id (0 objects without assigned changeset)")+"</li>"
-                    + "<li>"+tr("<b>nodes:</b>... - object with given number of nodes (nodes:count or nodes:min-max)")+"</li>"
-                    + "<li>"+tr("<b>tags:</b>... - object with given number of tags (tags:count or tags:min-max)")+"</li>"
+                    + "<li>"+tr("<b>nodes:</b>... - object with given number of nodes (nodes:count, nodes:min-max, nodes:min- or nodes:-max)")+"</li>"
+                    + "<li>"+tr("<b>tags:</b>... - object with given number of tags (nodes:count, nodes:min-max, nodes:min- or nodes:-max)")+"</li>"
                     + "<li>"+tr("<b>role:</b>... - object with given role in a relation")+"</li>"
                     + "<li>"+tr("<b>timestamp:</b>... -  objects with this timestamp (<b>2009-11-12T14:51:09Z</b>, <b>2009-11-12</b> or <b>T14:51</b> ...)")+"</li>"
-                    + "<li>"+tr("<b>areasize:</b>... - closed ways with area between MIN and MAX m\u00b2. (areasize:MIN-MAX or areasize:MAX)")+"</li>"
+                    + "<li>"+tr("<b>areasize:</b>... - closed ways with given area in m\u00b2 (areasize:min-max or areasize:max)")+"</li>"
                     + "<li>"+tr("<b>modified</b> - all changed objects")+"</li>"
                     + "<li>"+tr("<b>selected</b> - all selected objects")+"</li>"
Index: /trunk/src/org/openstreetmap/josm/actions/search/SearchCompiler.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/search/SearchCompiler.java	(revision 4345)
+++ /trunk/src/org/openstreetmap/josm/actions/search/SearchCompiler.java	(revision 4346)
@@ -509,41 +509,72 @@
     }
 
-    private static class NodeCountRange extends Match {
+    private abstract static class CountRange extends Match {
+
         private int minCount;
         private int maxCount;
+
+        public CountRange(int minCount, int maxCount) {
+            this.minCount = Math.min(minCount, maxCount);
+            this.maxCount = Math.max(minCount, maxCount);
+        }
+
+        protected abstract Integer getCount(OsmPrimitive osm);
+
+        protected abstract String getCountString();
+
+        @Override
+        public boolean match(OsmPrimitive osm) {
+            Integer count = getCount(osm);
+            if (count == null) {
+                return false;
+            } else {
+                return (count >= minCount) && (count <= maxCount);
+            }
+        }
+
+        @Override
+        public String toString() {
+            return getCountString() + "=" + minCount + "-" + maxCount;
+        }
+    }
+
+
+
+    private static class NodeCountRange extends CountRange {
+
         public NodeCountRange(int minCount, int maxCount) {
-            if(maxCount < minCount) {
-                this.minCount = maxCount;
-                this.maxCount = minCount;
-            } else {
-                this.minCount = minCount;
-                this.maxCount = maxCount;
-            }
-        }
-        @Override public boolean match(OsmPrimitive osm) {
-            if(!(osm instanceof Way)) return false;
-            int size = ((Way)osm).getNodesCount();
-            return (size >= minCount) && (size <= maxCount);
-        }
-        @Override public String toString() {return "nodes="+minCount+"-"+maxCount;}
-    }
-
-    private static class TagCountRange extends Match {
-        private int minCount;
-        private int maxCount;
+            super(minCount, maxCount);
+        }
+
+        @Override
+        protected Integer getCount(OsmPrimitive osm) {
+            if (!(osm instanceof Way)) {
+                return null;
+            } else {
+                return ((Way) osm).getNodesCount();
+            }
+        }
+
+        @Override
+        protected String getCountString() {
+            return "nodes";
+        }
+    }
+
+    private static class TagCountRange extends CountRange {
+
         public TagCountRange(int minCount, int maxCount) {
-            if(maxCount < minCount) {
-                this.minCount = maxCount;
-                this.maxCount = minCount;
-            } else {
-                this.minCount = minCount;
-                this.maxCount = maxCount;
-            }
-        }
-        @Override public boolean match(OsmPrimitive osm) {
-            int size = osm.getKeys().size();
-            return (size >= minCount) && (size <= maxCount);
-        }
-        @Override public String toString() {return "tags="+minCount+"-"+maxCount;}
+            super(minCount, maxCount);
+        }
+
+        @Override
+        protected Integer getCount(OsmPrimitive osm) {
+            return osm.getKeys().size();
+        }
+
+        @Override
+        protected String getCountString() {
+            return "tags";
+        }
     }
 
@@ -637,22 +668,22 @@
      * @author Ole Jørgen Brønner
      */
-    private static class Area extends Match {
-        private int min, max;
-
-        public Area(int min, int max) {
-            this.min = min;
-            this.max = max;
-            if (min == max) {
-                this.min = 0;
-            }
-        }
-
-        @Override
-        public boolean match(OsmPrimitive osm) {
-            if(!(osm instanceof Way && ((Way) osm).isClosed()))
-                return false;
-            Way way = (Way)osm;
-            double area = Geometry.closedWayArea(way);
-            return (min <= area && area <= max);
+    private static class Area extends CountRange {
+
+        public Area(int minCount, int maxCount) {
+            super(minCount, maxCount);
+        }
+
+        @Override
+        protected Integer getCount(OsmPrimitive osm) {
+            if (!(osm instanceof Way && ((Way) osm).isClosed())) {
+                return null;
+            }
+            Way way = (Way) osm;
+            return (int) Geometry.closedWayArea(way);
+        }
+
+        @Override
+        protected String getCountString() {
+            return "area";
         }
     }
