import java.io.*; import java.util.*; public class JaroWinkler { public static void main(String[] args) { try { List words = loadDictionary("linuxwords.txt"); String[] strings = { "accomodate", "definately", "goverment", "occured", "publically", "recieve", "seperate", "untill", "wich" }; for (String string : strings) { System.out.printf("Close dictionary words (distance < 0.15 using Jaro-Winkler distance) to '%s' are:\n" + " Word | Distance\n", string); for (StringDistance s : withinDistance(words, 0.15, string, 5)) { System.out.printf("%14s | %.4f\n", s.word, s.distance); } System.out.println(); } } catch (Exception e) { e.printStackTrace(); } } private static class StringDistance implements Comparable { private StringDistance(String word, double distance) { this.word = word; this.distance = distance; } public int compareTo(StringDistance s) { return Double.compare(distance, s.distance); } private String word; private double distance; } private static List withinDistance(List words, double maxDistance, String string, int max) { List result = new ArrayList<>(); for (String word : words) { double distance = jaroWinklerDistance(word, string); if (distance <= maxDistance) result.add(new StringDistance(word, distance)); } Collections.sort(result); if (result.size() > max) result = result.subList(0, max); return result; } private static double jaroWinklerDistance(String string1, String string2) { int len1 = string1.length(); int len2 = string2.length(); if (len1 < len2) { String s = string1; string1 = string2; string2 = s; int tmp = len1; len1 = len2; len2 = tmp; } if (len2 == 0) return len1 == 0 ? 0.0 : 1.0; int delta = Math.max(1, len1 / 2) - 1; boolean[] flag = new boolean[len2]; Arrays.fill(flag, false); char[] ch1Match = new char[len1]; int matches = 0; for (int i = 0; i < len1; ++i) { char ch1 = string1.charAt(i); for (int j = 0; j < len2; ++j) { char ch2 = string2.charAt(j); if (j <= i + delta && j + delta >= i && ch1 == ch2 && !flag[j]) { flag[j] = true; ch1Match[matches++] = ch1; break; } } } if (matches == 0) return 1.0; int transpositions = 0; for (int i = 0, j = 0; j < len2; ++j) { if (flag[j]) { if (string2.charAt(j) != ch1Match[i]) ++transpositions; ++i; } } double m = matches; double jaro = (m / len1 + m / len2 + (m - transpositions / 2.0) / m) / 3.0; int commonPrefix = 0; len2 = Math.min(4, len2); for (int i = 0; i < len2; ++i) { if (string1.charAt(i) == string2.charAt(i)) ++commonPrefix; } return 1.0 - (jaro + commonPrefix * 0.1 * (1.0 - jaro)); } private static List loadDictionary(String path) throws IOException { try (BufferedReader reader = new BufferedReader(new FileReader(path))) { List words = new ArrayList<>(); String word; while ((word = reader.readLine()) != null) words.add(word); return words; } } }