Skip to content

Commit

Permalink
Simplied fuzzy matching code
Browse files Browse the repository at this point in the history
  • Loading branch information
mjrichmond committed Aug 24, 2014
1 parent af2caca commit 64d6a32
Showing 1 changed file with 30 additions and 76 deletions.
106 changes: 30 additions & 76 deletions Window Walker/Window Walker/Components/FuzzyMatching.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,87 +20,48 @@ public class FuzzyMatching
/// </summary>
/// <param name="text">The text to search inside of</param>
/// <param name="searchText">the text to search for</param>
/// <returns></returns>
/// <returns>The best fuzzy match</returns>
public static List<int> FindBestFuzzyMatch(string text, string searchText, int searchStartIndex = 0)
{
List<int> matchIndexes = new List<int>();

searchText = searchText.ToLower();
text = text.ToLower();

// Create a grid to march matches like
// eg.
// a b c a d e c f g
// a x x
// c x x
bool[,] matches = new bool[text.Length, searchText.Length];
for (int firstIndex = 0; firstIndex < text.Length; firstIndex++ )
{
for(int secondIndex = 0; secondIndex < searchText.Length; secondIndex++)
{
matches[firstIndex, secondIndex] =
searchText[secondIndex] == text[firstIndex] ?
true :
false;
}
}
List<int> bestResult = null;
int bestResultScore = 0;

// use this table to get all the possible matches
List<List<int>> allMatches = FuzzyMatching.GetAllMatchIndexes(matches);

// return the score that is the max
int maxScore = allMatches.Count > 0 ? FuzzyMatching.CalculateScoreForMatches(allMatches[0]) : 0 ;
List<int> bestMatch = allMatches.Count > 0 ? allMatches[0] : new List<int>();

foreach(var match in allMatches)
for (int i = 0; i < text.Length; i++)
{
int score = FuzzyMatching.CalculateScoreForMatches(match);
if (score > maxScore)
if (text[i] == searchText[0])
{
bestMatch = match;
maxScore = score;
}
}

return bestMatch;
}

/// <summary>
/// Gets all the possible matches to the search string with in the text
/// </summary>
/// <param name="matches"> a table showing the matches as generated by
/// a two dimentional array with the first dimention the text and the second
/// one the search string and each cell marked as an intersection between the two</param>
/// <returns>a list of the possible combinations that match the search text</returns>
public static List<List<int>> GetAllMatchIndexes(bool[,] matches)
{
List<List<int>> results = new List<List<int>>();
// The charcter at index i matches the first character in the search string
List<int> currentResult = new List<int> { i };

for (int secondIndex = 0; secondIndex < matches.GetLength(1); secondIndex++)
{
for (int firstIndex = 0; firstIndex < matches.GetLength(0); firstIndex++)
{
if (secondIndex == 0 && matches[firstIndex,secondIndex])
// Loop through trying to find all of the rest of the characters in the search string
int currentNeedleIndex = 1;
for (int j = (i + 1); j < searchText.Length && currentNeedleIndex < searchText.Length; j++)
{
results.Add(new List<int> { firstIndex });
if (text[j] == searchText[currentNeedleIndex])
{
// We found the character. Add the index and then increment it so we start looking
// for the next character in the search string
currentResult.Add(j);
currentNeedleIndex++;
}
}
else if (matches[firstIndex, secondIndex])

if (currentNeedleIndex == searchText.Length)
{
var tempList = results.Where(x => x.Count == secondIndex && x[x.Count-1] < firstIndex).Select(x => x.ToList()).ToList();

foreach(var pathSofar in tempList)
// We got through the entire string
int currentResultScore = CalculateScoreForMatches(currentResult);

if (bestResult == null || currentResultScore < bestResultScore)
{
pathSofar.Add(firstIndex);
// This result is better than the best match we have so far
bestResult = currentResult;
bestResultScore = currentResultScore;
}

results.AddRange(tempList);
}
}

results = results.Where(x => x.Count == secondIndex + 1).ToList();
}

return results.Where(x => x.Count == matches.GetLength(1)).ToList();
return (bestResult != null) ? bestResult : new List<int>();
}

/// <summary>
Expand All @@ -110,16 +71,9 @@ public static List<List<int>> GetAllMatchIndexes(bool[,] matches)
/// <returns>an integer representing the score</returns>
public static int CalculateScoreForMatches(List<int> matches)
{
var score = 0;

for (int currentIndex = 1; currentIndex < matches.Count; currentIndex++)
{
var previousIndex = currentIndex - 1;

score -= (matches[currentIndex] - matches[previousIndex]);
}

return score == 0 ? -10000 : score;
// Note: The matches are in ascending order to the score is simply the index of
// the last letter minus the index of the first letter.
return (matches.Count > 1) ? (matches[matches.Count -1] - matches[0]) : -10000;
}
}

Expand Down

0 comments on commit 64d6a32

Please sign in to comment.