高性能なスペルミス修正アルゴリズムをHow to Write a Spelling Correctorで見つけたので紹介します。
リンク先では、理論的背景とコードも説明されていますので、参考になるかと思います。
ここのJavaバージョンのコードを私なりに書き直してみました。
package com.dukesoftware.spellcorrector; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; public class SpellCorrector { public static void main(String args[]) throws IOException { Map<String, Integer> nWords = new HashMap<String, Integer>() {{ put("spell", 1); }}; SpellCorrector spellCorrector = new SpellCorrector(nWords); System.out.println(spellCorrector.correct("superl")); } private final Map<String, Integer> nWords; private final String[] a_to_z; public SpellCorrector(Map<String, Integer> nWords) throws IOException { this.nWords = nWords; this.a_to_z = createAtoZStringArray(); } private String[] createAtoZStringArray() { String[] a_to_z = new String['z' - 'a' + 1]; for(char c = 'a'; c <= 'z'; ++c) { a_to_z[c-'a'] = String.valueOf(c); } return a_to_z; } private List<String> edits(String word) { List<String> result = new ArrayList<>(); final int len = word.length(); final int len_m1 = len - 1; final String[] a_to_z = this.a_to_z; for (int i = 0; i < len_m1; ++i) { final String top = word.substring(0, i); final String middle = word.substring(i); final String bottom = word.substring(i + 1); result.add(top + bottom); for (String c : a_to_z) { result.add(top + c + bottom); result.add(top + c + middle); } result.add(top + word.substring(i + 1, i + 2) + word.substring(i, i + 1) + word.substring(i + 2)); } final String word_0_len = word.substring(0, len); final String word_0_len_m1 = word.substring(0, len_m1); final String word_len = word.substring(len); final String word_len_m1 = word.substring(len_m1); result.add(word_0_len_m1 + word_len); for (String c : a_to_z) { result.add(word_0_len_m1 + c + word_len); result.add(word_0_len_m1 + c + word_len_m1); result.add(word_0_len + c + word_len); } return result; } public final String correct(String word) { if (nWords.containsKey(word)) { return word; } List<String> list = edits(word); Map<Integer, String> candidates = new HashMap<>(); for (String s : list) { putToCandidates(s, candidates); } if (candidates.size() > 0) { return candidates.get(Collections.max(candidates.keySet())); } for (String s : list) { for (String w : edits(s)) { putToCandidates(w, candidates); } } return candidates.size() > 0 ? candidates.get(Collections.max(candidates.keySet())) : word; } private void putToCandidates(String w, Map<Integer, String> candidates) { if (nWords.containsKey(w)) { candidates.put(nWords.get(w), w); } } }
コメント