WIP
DirectOutput framework for virtual pinball cabinets WIP
Go to:
Overview 
FuzzyText.cs
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  * modified by Tyler Jensen from
3  * http://www.codeguru.com/vb/gen/vb_misc/algorithms/article.php/c13137__1/Fuzzy-Matching-Demo-in-Access.htm
4  * Also see http://www.berghel.net/publications/asm/asm.php
5  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6 
7 using System;
8 using System.Collections.Generic;
9 
10 using System.Text;
11 
12 namespace FuzzyStrings
13 {
14  public static class FuzzyText
15  {
24  public static double Levenshtein(string input, string comparedTo, bool caseSensitive = false)
25  {
26  if (string.IsNullOrEmpty(input) || string.IsNullOrEmpty(comparedTo)) return 999;
27  if (!caseSensitive)
28  {
29  input = input.ToLower();
30  comparedTo = comparedTo.ToLower();
31  }
32  int inputLen = input.Length;
33  int comparedToLen = comparedTo.Length;
34 
35  int[,] matrix = new int[inputLen, comparedToLen];
36 
37  //initialize
38  for (int i = 0; i < inputLen; i++) matrix[i, 0] = i;
39  for (int i = 0; i < comparedToLen; i++) matrix[0, i] = i;
40 
41  //analyze
42  for (int i = 1; i < inputLen; i++)
43  {
44  var si = input[i - 1];
45  for (int j = 1; j < comparedToLen; j++)
46  {
47  var tj = comparedTo[j - 1];
48  int cost = (si == tj) ? 0 : 1;
49 
50  var above = matrix[i - 1, j];
51  var left = matrix[i, j - 1];
52  var diag = matrix[i - 1, j - 1];
53  var cell = FindMinimum(above + 1, left + 1, diag + cost);
54 
55  //transposition
56  if (i > 1 && j > 1)
57  {
58  var trans = matrix[i - 2, j - 2] + 1;
59  if (input[i - 2] != comparedTo[j - 1]) trans++;
60  if (input[i - 1] != comparedTo[j - 2]) trans++;
61  if (cell > trans) cell = trans;
62  }
63  matrix[i, j] = cell;
64  }
65  }
66  return (double)1/(1+matrix[inputLen - 1, comparedToLen - 1]);
67  }
68 
69  private static int FindMinimum(params int[] p)
70  {
71  if (null == p) return int.MinValue;
72  int min = int.MaxValue;
73  for (int i = 0; i < p.Length; i++)
74  {
75  if (min > p[i]) min = p[i];
76  }
77  return min;
78  }
79 
80 
81 
89  public static double DiceCoefficient(string input, string comparedTo)
90  {
91  var ngrams = ToBiGrams(input);
92  var compareToNgrams = ToBiGrams(comparedTo);
93  return DiceCoefficient(ngrams,compareToNgrams);
94  }
95 
102  private static double DiceCoefficient( string[] nGrams, string[] compareToNGrams)
103  {
104  int matches = 0;
105  foreach (var nGram in nGrams)
106  {
107  foreach (string x in compareToNGrams)
108  {
109  if (x == nGram)
110  {
111  matches++;
112  break;
113  }
114  }
115  }
116  if (matches == 0) return 0.0d;
117  double totalBigrams = nGrams.Length + compareToNGrams.Length;
118  return (2 * matches) / totalBigrams;
119  }
120 
121  private static string[] ToBiGrams( string input)
122  {
123  // nLength == 2
124  // from Jackson, return %j ja ac ck ks so on n#
125  // from Main, return #m ma ai in n#
126  input = SinglePercent + input + SinglePound;
127  return ToNGrams(input, 2);
128  }
129 
130  private static string[] ToTriGrams( string input)
131  {
132  // nLength == 3
133  // from Jackson, return %%j %ja jac ack cks kso son on# n##
134  // from Main, return ##m #ma mai ain in# n##
135  input = DoublePercent + input + DoublePount;
136  return ToNGrams(input, 3);
137  }
138 
139  private static string[] ToNGrams(string input, int nLength)
140  {
141  int itemsCount = input.Length - 1;
142  string[] ngrams = new string[input.Length - 1];
143  for (int i = 0; i < itemsCount; i++) ngrams[i] = input.Substring(i, nLength);
144  return ngrams;
145  }
146 
147  private const string SinglePercent = "%";
148  private const string SinglePound = "#";
149  private const string DoublePercent = "&&";
150  private const string DoublePount = "##";
151 
152  }
153 }