public static SearchResult <T> Find <T>(IEnumerable <T> collection, string input, Func <T, ISearchableProperty> searchProperties) { var normalizedInput = input.ToLower(); var lev = new Fastenshtein.Levenshtein(normalizedInput); var lowestDistance = int.MaxValue; var currentWinner = default(T); foreach (var item in collection) { foreach (var searchProperty in searchProperties(item).AsStrings) { var termToMatchAgainst = searchProperty.ToLower(); if (termToMatchAgainst == normalizedInput) { return(new SearchResult <T>(item, 0)); } var distance = lev.DistanceFrom(termToMatchAgainst); if (distance >= lowestDistance) { continue; } lowestDistance = distance; currentWinner = item; } } return(new SearchResult <T>(currentWinner, lowestDistance)); }
// Grab text from image private string GetText(TessBaseAPI tessBaseAPI, int partX, int partY) { // These can change depending on resolution, HUD scaling, or UI changes // For now, only supports 1440p with full HUD scaling // TODO: Dynamic scaling const int BOXWIDTH = 311; const int BOXHEIGHT = 33; // Set image location start tessBaseAPI.SetRectangle(partX, partY, BOXWIDTH, BOXHEIGHT); // Recognize image tessBaseAPI.Recognize(); ResultIterator resultIterator = tessBaseAPI.GetIterator(); // Extract text from result iterator StringBuilder stringBuilder = new StringBuilder(); PageIteratorLevel pageIteratorLevel = PageIteratorLevel.RIL_PARA; do { stringBuilder.Append(resultIterator.GetUTF8Text(pageIteratorLevel)); } while (resultIterator.Next(pageIteratorLevel)); // Fix up string for Warframe.market stringBuilder = stringBuilder.Replace("\n", String.Empty); string guess = stringBuilder.ToString(); // Changed to use Levenshtein here due to important of having a matching "Blueprint" word Levenshtein levBP = new Fastenshtein.Levenshtein("Blueprint"); int levBPDistance = levBP.DistanceFrom(guess); Debug.WriteLine("Distance from Blueprint: " + levBPDistance); // If there is a 4-character difference, accept the word is == "Blueprint" // Adjust the offset for 2-lined parts if (levBPDistance < 5) { guess = GetText(tessBaseAPI, partX, 550); } // Match whatever result we get to the closest selling item name from Warframe.market // We want to ignore "Blueprint" because this indicates that it's a 2-lined item if (guess != "Blueprint" && !guess.Contains("Forma")) { Debug.Write(""); Debug.Write("Old: " + guess); guess = FindClosestWord(guess); Debug.WriteLine(" | New: " + guess); } return(guess); }
private void SearchLev() { Debug.Log("Searching Lev now"); var stopwatch = new Stopwatch(); stopwatch.Start(); Levenshtein lev = new Levenshtein(searchTerm); for (var index = 0; index < termList.Count; index++) { var term = termList[index]; int levenshteinDistance = lev.DistanceFrom(term); } stopwatch.Stop(); Debug.Log("Lev terms in ticks: " + stopwatch.ElapsedTicks); Debug.Log("Break"); }
// The Levenshtein distance algorithm is awesome. This basically allows us to quickly compute the distance between words // This function is called when a proper json can't be found and tries to find the closest part from all currently known tradable parts private string FindClosestWord(string word) { Levenshtein lev = new Fastenshtein.Levenshtein(word); int minDistance = 9999; string potential = ""; using (StreamReader r = new StreamReader(@"items\items.json")) { string json = r.ReadToEnd(); JObject items = (JObject)JsonConvert.DeserializeObject(json); foreach (var item in items["payload"]["items"]) { string currentItem = item["item_name"].ToString(); //.ToUpper(); int levenshteinDistance = lev.DistanceFrom(currentItem); //Debug.WriteLine((string)item["item_name"] + " | " + levenshteinDistance); if (minDistance > levenshteinDistance) { minDistance = levenshteinDistance; potential = currentItem; } } } // Arbitrary value; needs more testing for the sweetspot /*if (minDistance <= 15) * { * return potential; * } * return word; */ return(potential); }