Skip to content

Commit 4955fdf

Browse files
authored
Add files via upload
1 parent bf848d5 commit 4955fdf

1 file changed

Lines changed: 26 additions & 32 deletions

File tree

SymSpellCompound.cs

Lines changed: 26 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
// Author: Wolf Garbe <wolf.garbe@faroo.com>
2121
// Maintainer: Wolf Garbe <wolf.garbe@faroo.com>
2222
// URL: https://github.com/wolfgarbe/SymSpellCompound
23-
// Description: https://github.com/wolfgarbe/SymSpellCompound
23+
// Description: https://medium.com/wolfgarbe/symspellcompound-10ec8f467c9b
2424
//
2525
// License:
2626
// This program is free software; you can redistribute it and/or modify
@@ -77,7 +77,6 @@ public override int GetHashCode()
7777
return term.GetHashCode();
7878
}
7979

80-
//http://www.cshandler.com/2012/07/shallow-copy-and-deep-copy-using.html#.WQMxhVWGNaQ
8180
public suggestItem ShallowCopy()
8281
{
8382
return (suggestItem)MemberwiseClone();
@@ -101,19 +100,19 @@ private static IEnumerable<string> parseWords(string text)
101100
{
102101
// \w Alphanumeric characters (including non-latin characters, umlaut characters and digits) plus "_"
103102
// \d Digits
104-
// Provides identical results to Norvigs regex "[a-z]+" for latin characters, while additionally providing compatibility with non-latin characters
105-
106-
//for benchmarking only, to provide the exact same number of dictionary items to Norvig's algorithm, but splits words at apostrophes
107-
//return Regex.Matches(text.ToLower(), @"[\w-[\d_]]+").Cast<Match>().Select(m => m.Value);
103+
// Compatible with non-latin characters, does not split words at apostrophes
108104
return Regex.Matches(text.ToLower(), @"['’\w-[_]]+").Cast<Match>().Select(m => m.Value);
105+
106+
//for benchmarking only: with CreateDictionary("big.txt","") and the text corpus from http://norvig.com/big.txt the Regex below provides the exact same number of dictionary items as Norvigs regex "[a-z]+" (which splits words at apostrophes & incompatible with non-latin characters)
107+
//return Regex.Matches(text.ToLower(), @"[\w-[\d_]]+").Cast<Match>().Select(m => m.Value);
109108
}
110109

111110
public static int maxlength = 0;//maximum dictionary term length
112111

113112
//for every word there all deletes with an edit distance of 1..editDistanceMax created and added to the dictionary
114113
//every delete entry has a suggestions list, which points to the original term(s) it was created from
115114
//The dictionary may be dynamically updated (word frequency and new words) at any time by calling createDictionaryEntry
116-
private static bool CreateDictionaryEntry(string key, string language, Int64 count) //count=0 : value.count++/ count>0 : value.count=count
115+
private static bool CreateDictionaryEntry(string key, string language, Int64 count)
117116
{
118117
//a treshold might be specifid, when a term occurs so frequently in the corpus that it is considered a valid word for spelling correction
119118
int countTreshold = 1;
@@ -141,16 +140,14 @@ private static bool CreateDictionaryEntry(string key, string language, Int64 cou
141140
}
142141

143142
countPrevious = value.count;
144-
//summarizes multiple frequency entries of a word
145-
if (count > 0) value.count +=count;
146-
//prevent overflow (repetitions of a word)
147-
else if (value.count < Int64.MaxValue) value.count++;
143+
//summarizes multiple frequency entries of a word (prevents overflow)
144+
value.count = Math.Min(Int64.MaxValue, value.count + count);
148145
}
149146
else
150147
{
151148
//new word
152149
value = new dictionaryItem();
153-
if (count > 0) value.count = count; else value.count++;
150+
value.count = count;
154151
itemlist.Add(value);
155152
dictionary[language + key] = -itemlist.Count;
156153

@@ -267,8 +264,7 @@ private static void CreateDictionary(string corpus, string language)
267264
{
268265
foreach (string key in parseWords(line))
269266
{
270-
if ((key.Length == 1) && (key != "a") && (key != "i")) continue;
271-
if (CreateDictionaryEntry(key, language,0)) wordCount++;
267+
if (CreateDictionaryEntry(key, language,1)) wordCount++;
272268
}
273269
}
274270
}
@@ -342,16 +338,14 @@ private static List<suggestItem> Lookup(string input, string language, int editD
342338
if (valueo >= 0) value.suggestions.Add((Int32)valueo); else value = itemlist[-valueo - 1];
343339

344340
//if count>0 then candidate entry is correct dictionary term, not only delete item
345-
//if ((value.count > 0) && hashset2.Add(candidate))
346-
//New: supress short, infrequent terms as suggestion, because that are probably spelling errors that made it to the dictionary
347-
if (((value.count > 100)||((candidate.Length > 2)&&(value.count > 0)) ) && hashset2.Add(candidate))
341+
if ((value.count > 0) && hashset2.Add(candidate))
348342
{
349343
int distance = input.Length - candidate.Length;
350344
//save some time
351345
//do not process higher distances than those already found, if verbose<2
352346
if ((verbose == 2) || (suggestions.Count == 0) || (distance <= suggestions[0].distance))
353347
{
354-
//Fix: previously not allways all suggestions were returned for verbose<2 : e.g. elove did not return love (edit distance=0)
348+
//Fix: previously not allways all suggestons within editdistance (verbose=1) or the best suggestion (verbose=0) were returned : e.g. elove did not return love
355349
//suggestions.Clear() was not executed in this branch, if a suggestion with lower edit distance was added here (for verbose<2).
356350
//Then possibly suggestions with higher edit distance remained on top, the suggestion with lower edit distance were added to the end.
357351
//All of them where deleted later once a suggestion with a lower distance than the first item in the list was later added in the other branch.
@@ -416,13 +410,9 @@ private static List<suggestItem> Lookup(string input, string language, int editD
416410
si.count = itemlist[-value2 - 1].count;
417411
si.distance = distance;
418412

419-
//New: supress short, infrequent terms as suggestion, because that are probably spelling errors that made it to the dictionary
420-
if ((si.count > 100) || (suggestion.Length > 2))
421-
{
422-
//remove all existing suggestions of higher distance, if verbose<2
423-
if ((verbose < 2) && (suggestions.Count > 0) && (suggestions[0].distance > distance)) suggestions.Clear();
424-
suggestions.Add(si);
425-
}
413+
//remove all existing suggestions of higher distance, if verbose<2
414+
if ((verbose < 2) && (suggestions.Count > 0) && (suggestions[0].distance > distance)) suggestions.Clear();
415+
suggestions.Add(si);
426416
}
427417
}
428418
}
@@ -461,7 +451,7 @@ private static void Correct(string input, string language)
461451
//display term and frequency
462452
foreach (var suggestion in suggestions)
463453
{
464-
Console.WriteLine( suggestion.term + " " + suggestion.distance.ToString() + " " + suggestion.count.ToString());
454+
Console.WriteLine( suggestion.term + " " + suggestion.distance.ToString() + " " + suggestion.count.ToString("N0"));
465455
}
466456
if (verbose !=0) Console.WriteLine(suggestions.Count.ToString() + " suggestions");
467457
}
@@ -605,20 +595,24 @@ private static void ReadFromStdIn()
605595
}
606596
}
607597

598+
//Load a frequency dictionary or create a frequency dictionary from a text corpus
608599
public static void Main(string[] args)
609600
{
610-
//Create the dictionary from a sample corpus
611-
//e.g. http://norvig.com/big.txt , or any other large text corpus
601+
//Manually curating/cleaning up the dictionary or using a professional frequency dictionary will increase the precision of the spelling correction.
602+
//Load a frequency dictionary
603+
LoadDictionary("wordfrequency_en.txt", "", 0, 1);
604+
605+
//Create the dictionary from a text corpus (e.g. http://norvig.com/big.txt )
606+
//Make sure the corpus does not contain spelling errors, invalid terms and the word frequency is representative to increase the precision of the spelling correction.
607+
//
612608
//The dictionary may contain vocabulary from different languages.
613609
//If you use mixed vocabulary use the language parameter in Correct() and CreateDictionary() accordingly.
610+
//
614611
//You may use CreateDictionaryEntry() to update a (self learning) dictionary incrementally
612+
//
615613
//To extend spelling correction beyond single words to phrases (e.g. correcting "unitedkingom" to "united kingdom") simply add those phrases with CreateDictionaryEntry().
616614
//CreateDictionary("big.txt","");
617615

618-
//Manually curating/cleaning up the dictionary or using a professional frequency dictionary will increase the precision of the suggestions.
619-
//Load a frequency dictionary
620-
LoadDictionary("wordfrequency_en.txt", "", 0, 1);
621-
622616
ReadFromStdIn();
623617
}
624618

0 commit comments

Comments
 (0)