Beispiel #1
0
 /// <summary>
 /// 2つのハッシュ値の距離を計算する。
 /// </summary>
 /// <param name="a">ハッシュ値</param>
 /// <param name="b">ハッシュ値</param>
 /// <returns>ハッシュ値の距離</returns>
 public static int MeasureDistance(WordHash a, WordHash b)
 {
     var ab1 = a.val1 & b.val1;
     var ab2 = a.val2 & b.val2;
     if (ab1 == 0 && ab2 == 0)
     {
         return int.MaxValue;
     }
     else
     {
         return Math.Max(
             countBits(a.val1 - ab1) + countBits(a.val2 - ab2),
             countBits(b.val1 - ab1) + countBits(b.val2 - ab2)
             );
     }
 }
        /// <summary>
        /// 正しい単語リストの中から、指定した文字列に近い単語を取得する。
        /// 専用のハッシュ値を使って単語を絞ってから、レーベンシュタイン距離を使って処理する。
        /// </summary>
        /// <param name="word">文字列</param>
        /// <param name="candidatesCount">絞る単語の個数の最小値</param>
        /// <returns></returns>
        public ProofreaderResult Proofread(string word, int candidatesCount = 5)
        {
            // 元から正しい単語ならそのまま返す
            if (hashes.ContainsKey(word))
            {
                return new ProofreaderResult(word, new List<string> { word });
            }

            // 辞書の各単語とのハッシュ距離を計算する
            var hash = new WordHash(word);
            var allWords = hashes.Keys.ToList(); // うーん
            var hashDists = new int[allWords.Count];
            for (var i = 0; i < allWords.Count; ++i)
            {
                hashDists[i] = WordHash.MeasureDistance(hash, hashes[allWords[i]]);
            }
            var candidates = new List<string>();
            for (var dist = 0; candidates.Count < candidatesCount; ++dist)
            {
                for (var i = 0; i < allWords.Count; ++i)
                {
                    if (hashDists[i] == dist)
                    {
                        candidates.Add(allWords[i]);
                    }
                }
            }

            #region debug print
            if (DebugPrint)
            {
                var distList = Enumerable.Range(0, allWords.Count)
                    .Select(i => Tuple.Create(allWords[i], hashDists[i]))
                    .ToList();
                distList.Sort((a, b) => a.Item2.CompareTo(b.Item2));
                Console.Error.WriteLine("word: {0}", word);
                foreach (var distPair in distList)
                {
                    Console.Error.WriteLine("{0}\t{1}", distPair.Item2, distPair.Item1);
                }
            }
            #endregion

            // 候補の中でレーベンシュタイン距離が最も近いものを返す
            var min = int.MaxValue;
            var res = new List<string>();
            foreach (var cw in candidates)
            {
                var dist = MeasureLevenshtein(word, cw);
                if (dist < min)
                {
                    min = dist;
                    res = new List<string> { cw };
                }
                else if (dist == min)
                {
                    res.Add(cw);
                }
            }
            return new ProofreaderResult(word, res);
        }