Index: src/org/openstreetmap/josm/tools/StringMetrics.java
===================================================================
--- src/org/openstreetmap/josm/tools/StringMetrics.java	(revision 0)
+++ src/org/openstreetmap/josm/tools/StringMetrics.java	(working copy)
@@ -0,0 +1,116 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.tools;
+
+/**
+ * Provides methods for computing similarity between strings.
+ */
+public final class StringMetrics {
+    private static final LevenshteinStringMetric levenshtein = new LevenshteinStringMetric();
+    
+    /**
+     * Get metric by name.
+     * 
+     * @param name
+     * @return 
+     */
+    public static InterfaceStringMetric getByName(String name) {
+        if ("levenshtein".equals(name)) {
+            return levenshtein;
+        }
+        throw new IllegalArgumentException("Not a valid string metric name");
+    }
+
+    public interface InterfaceStringMetric {
+        /**
+         * Get string similarity. 1 indicates a perfect match and 0 indicates no match
+         * 
+         * @param string1 First string
+         * @param string2 Second string
+         * @return the similarity between the strings normalized
+         */
+        public float getSimilarity(String string1, String string2);
+
+        /**
+         * Get unnormalized similarity; the range of possible values may vary
+         * between metrics
+         * 
+         * @param string1 first string
+         * @param string2 second string
+         * @return 
+         */
+        public float getUnNormalisedSimilarity(String string1, String string2);
+    }
+
+    /**
+     * Compute Levenshtein distance. For algorithm details see:
+     * http://en.wikipedia.org/wiki/Levenshtein_distance
+     */
+    public static class LevenshteinStringMetric implements InterfaceStringMetric {
+
+        @Override
+        public float getSimilarity(String string1, String string2) {
+            float d = getUnNormalisedSimilarity(string1, string2);
+            int max = Math.max(string1.length(), string2.length());
+            if (max > 0)
+                return 1 - (d/(float)max);
+            else
+                return 1;
+        }
+
+        @Override
+        public float getUnNormalisedSimilarity(String string1, String string2) {
+            int d[][]; // matrix
+            int n; // length of s
+            int m; // length of t
+            int i; // iterates through s
+            int j; // iterates through t
+            char s_i; // ith character of s
+            char t_j; // jth character of t
+            int cost; // cost
+
+            // Step 1
+            n = string1.length();
+            m = string2.length();
+            if (n == 0) {
+                return m;
+            }
+            if (m == 0) {
+                return n;
+            }
+            d = new int[n + 1][m + 1];
+
+            // Step 2
+            for (i = 0; i <= n; i++) {
+                d[i][0] = i;
+            }
+            for (j = 0; j <= m; j++) {
+                d[0][j] = j;
+            }
+
+            // Step 3
+            for (i = 1; i <= n; i++) {
+
+                s_i = string1.charAt(i - 1);
+
+                // Step 4
+                for (j = 1; j <= m; j++) {
+
+                    t_j = string2.charAt(j - 1);
+
+                    // Step 5
+                    if (s_i == t_j) {
+                        cost = 0;
+                    } else {
+                        cost = 1;
+                    }
+
+                    // Step 6
+                    d[i][j] = Utils.min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + cost);
+                }
+            }
+
+            // Step 7
+            return d[n][m];
+        }
+    }
+}
Index: src/org/openstreetmap/josm/data/validation/tests/SimilarNamedWays.java
===================================================================
--- src/org/openstreetmap/josm/data/validation/tests/SimilarNamedWays.java	(revision 5061)
+++ src/org/openstreetmap/josm/data/validation/tests/SimilarNamedWays.java	(working copy)
@@ -17,7 +17,7 @@
 import org.openstreetmap.josm.data.validation.util.ValUtil;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 import org.openstreetmap.josm.tools.MultiMap;
-import org.openstreetmap.josm.tools.Utils;
+import org.openstreetmap.josm.tools.StringMetrics;
 
 /**
  * Checks for similar named ways, symptom of a possible typo. It uses the
@@ -77,7 +77,7 @@
                     continue;
                 }
 
-                int levenshteinDistance = getLevenshteinDistance(name, name2);
+                float levenshteinDistance = StringMetrics.getByName("levenshtein").getUnNormalisedSimilarity(name, name2);
                 if (0 < levenshteinDistance && levenshteinDistance <= 2) {
                     List<OsmPrimitive> primitives = new ArrayList<OsmPrimitive>();
                     primitives.add(w);
@@ -89,64 +89,4 @@
             ways.add(w);
         }
     }
-
-    /**
-     * Compute Levenshtein distance
-     *
-     * @param s First word
-     * @param t Second word
-     * @return The distance between words
-     */
-    public int getLevenshteinDistance(String s, String t) {
-        int d[][]; // matrix
-        int n; // length of s
-        int m; // length of t
-        int i; // iterates through s
-        int j; // iterates through t
-        char s_i; // ith character of s
-        char t_j; // jth character of t
-        int cost; // cost
-
-        // Step 1
-        n = s.length();
-        m = t.length();
-        if (n == 0)
-            return m;
-        if (m == 0)
-            return n;
-        d = new int[n + 1][m + 1];
-
-        // Step 2
-        for (i = 0; i <= n; i++) {
-            d[i][0] = i;
-        }
-        for (j = 0; j <= m; j++) {
-            d[0][j] = j;
-        }
-
-        // Step 3
-        for (i = 1; i <= n; i++) {
-
-            s_i = s.charAt(i - 1);
-
-            // Step 4
-            for (j = 1; j <= m; j++) {
-
-                t_j = t.charAt(j - 1);
-
-                // Step 5
-                if (s_i == t_j) {
-                    cost = 0;
-                } else {
-                    cost = 1;
-                }
-
-                // Step 6
-                d[i][j] = Utils.min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + cost);
-            }
-        }
-
-        // Step 7
-        return d[n][m];
-    }
 }