目录
介绍
使用代码
测试/实施
介绍我永远找不到在互联网上解读单词的好方法。每个算法要么是蛮力,要么是排列。
蛮力的问题在于它是一个猜谜游戏......非常慢,或者如果你幸运的话,非常快。
排列的问题在于,一旦超过7个字符,就会使用大量内存。例如,一个12个字符的加扰单词有479,001,600个配置!
我终于明白,如果你对打乱的单词进行排序,然后对字典条目进行排序,那么如果我们将任何排序的字典条目等同于我们的排序打乱,那么它们一定是匹配的!
可能有一些奇特的机器学习算法可以做到这一点,但我的方法完美而即时。
使用代码您需要将您最喜欢的字典嵌入到您的项目中(为了速度和便携性)。
那里有很多免费的字典文件;这是我使用的... https://github.com/dwyl/english-words。
直接链接... https://raw.githubusercontent.com/dwyl/english-words/master/words.txt。
主力就是UnscrambleWord方法;这将负责加载字典、过滤然后对结果进行排序并将它们存储在一个List对象中,该对象将从调用中返回给您。
class Unscramble
{
private static bool _dictionaryLoaded = false;
private static string _wordToUnscramble = "";
private static int _totalEntries = 0;
private static Dictionary _sortedDictionary =
new Dictionary();
private static List _results = new List();
private static Stopwatch _stopwatch;
//====================================================================================
/** We don't really need a constructor **/
//public Unscramble(string wordToUnscramble)
//{
// _WordToUnscramble = wordToUnscramble;
//}
//====================================================================================
public List UnscrambleWord(string wordToUnscramble, bool useFiltering = true)
{
_stopwatch = Stopwatch.StartNew();
if (string.IsNullOrEmpty(_wordToUnscramble))
{
_wordToUnscramble = wordToUnscramble;
}
else if (!_wordToUnscramble.Equals
(wordToUnscramble, StringComparison.OrdinalIgnoreCase) && useFiltering)
{ //If re-using the object and the word is different,
//we'll need to reload the dictionary
_dictionaryLoaded = false;
_wordToUnscramble = wordToUnscramble;
_results.Clear();
}
else if (_wordToUnscramble.Equals
(wordToUnscramble, StringComparison.OrdinalIgnoreCase))
{
_results.Clear(); //we should clear the results array so they don't stack
}
if (!_dictionaryLoaded) //the first call will be slightly slower
LoadEmbeddedDictionary(wordToUnscramble.ToUpper(), useFiltering);
string scrambleSorted = SortWord(wordToUnscramble);
//var kvp = SortedDictionary.FirstOrDefault
//(p => SortedDictionary.Comparer.Equals(p.Value, scrambledSort));
var matchList = _sortedDictionary.Where
(kvp => kvp.Value == scrambleSorted).Select(kvp => kvp.Key).ToList();
if (matchList.Count > 0)
{
foreach (string result in matchList)
{
System.Diagnostics.Debug.WriteLine($"> Match: {result}");
_results.Add(result);
}
_stopwatch.Stop();
System.Diagnostics.Debug.WriteLine($"> Elapsed time: {_stopwatch.Elapsed}");
return _results;
}
else //no matches
{
_stopwatch.Stop();
_results.Clear();
System.Diagnostics.Debug.WriteLine($"> Elapsed time: {_stopwatch.Elapsed}");
return _results;
}
}
//==================================================================================
private static void LoadEmbeddedDictionary(string wordText, bool filter = false)
{
char[] delims = new char[1] { '\n' };
string[] chunks;
int chunkCount = 0;
if (filter)
chunks = global::Utility.Properties.Resources.
DictionaryNums.ToUpper().Split(delims);
else
chunks = global::Utility.Properties.Resources.
DictionaryNums.ToUpper().Split(delims);
System.Diagnostics.Debug.WriteLine($"> Length filter: {wordText.Length}");
_sortedDictionary.Clear();
foreach (string str in chunks)
{
chunkCount++;
if (filter)
{
//we're assuming the word will have at least 3 characters...
//I mean would you really need this program if it was only two?
if ((str.Length == wordText.Length) &&
str.Contains(wordText.Substring(0, 1)) &&
str.Contains(wordText.Substring(1, 1)) &&
str.Contains(wordText.Substring(2, 1))) //just checking the 1st,
//2nd & 3rd letter will trim our search considerably
{
try
{
_sortedDictionary.Add(str, SortWord(str));
}
catch
{
//probably a key collision, just ignore
}
}
}
else
{
try
{
_sortedDictionary.Add(str, SortWord(str));
}
catch
{
//probably a key collision, just ignore
}
}
}
System.Diagnostics.Debug.WriteLine($">
Loaded {_sortedDictionary.Count} possible matches out of {chunkCount.ToString()}");
_totalEntries = chunkCount;
_dictionaryLoaded = true;
}
//=================================================================================
private static string SortWord(string str)
{
return String.Concat(str.OrderBy(c => c));
/*** Character Array Method ***
return String.Concat(str.OrderBy(c => c).ToArray());
*******************************/
/*** Traditional Method ***
char[] chars = input.ToArray();
Array.Sort(chars);
return new string(chars);
***************************/
}
#region [Helper Methods]
//=================================================================================
public TimeSpan GetMatchTime()
{
return _stopwatch.Elapsed;
}
//=================================================================================
public List GetMatchResults()
{
return _results;
}
//=================================================================================
public int GetMatchCount()
{
return _results.Count;
}
//=================================================================================
public int GetFilterCount()
{
return _sortedDictionary.Count;
}
//=================================================================================
public int GetDictionaryCount()
{
return _totalEntries;
}
#endregion
}
要驱动代码,你会这样做......
string scrambled = "mctmouicnaino";
Unscramble obj1 = new Unscramble();
List results = obj1.UnscrambleWord(scrambled);
if (results.Count > 0)
{
Console.WriteLine($"> Total matches: {obj1.GetMatchCount()}");
foreach (string str in results)
{
Console.WriteLine($">> {str}");
}
Console.WriteLine($"> Total time: {obj1.GetMatchTime()}");
Console.WriteLine($"> Filtered set: {obj1.GetFilterCount()}
out of {obj1.GetDictionaryCount()}");
}
else
{
Console.WriteLine("> No matches available:
Check your spelling, or the dictionary may be missing this word.");
}
添加更多的LINQ方法来更改顺序、取顶部结果等,但这应该是对任何解读引擎基础的一个很好的补救措施。
https://www.codeproject.com/Tips/5299463/How-to-Unscramble-Any-Word