示例#1
0
        /// <summary>
        /// Ищет наиболее подходящие совпадения в коллекции для указанного слова.
        /// Сравнение символов начинается с конца слова, чем ближе символ к началу слова, тем меньше веса совпадение имеет.
        /// Пример: пара [краснЫй и краснОй] имеет меньший вес совпадения, чем пара [КРАСный и УСТный].
        /// </summary>
        /// <param name="word">Слово для поиска в коллекции.</param>
        /// <param name="collection">Коллекция, в которой искать совпадения.</param>
        /// <param name="minSameLetters">Минимальное кол-во совпадающих символов с конца слова.</param>
        /// <param name="maxSameLetters">
        /// Максимальное кол-во совпадающих символов с конца слова.
        /// Можно использовать <see cref="int.MaxValue"/> для сравнения всех символов слова.
        /// </param>
        public List <string> GetSimilars(string word, IEnumerable <string> collection, int minSameLetters, int maxSameLetters)
        {
            if (word == null || word.Length < minSameLetters)
            {
                return(null);
            }

            string foundWord = null;
            List <SimilarCandidate> candidates = new List <SimilarCandidate>();

            foreach (string str in collection)
            {
                if (str == word)
                {
                    foundWord = str;
                    break;
                }

                int sameLetters;
                int maxPosition = Math.Min(maxSameLetters, Math.Min(word.Length, str.Length));
                int weight      = this.GetSimilarityWeight(word, str, maxPosition, minSameLetters, out sameLetters);

                if (sameLetters >= minSameLetters)
                {
                    SimilarCandidate c = new SimilarCandidate()
                    {
                        Name   = str,
                        Weight = weight
                    };

                    candidates.Add(c);
                }
            }

            return(candidates
                   .AsParallel()
                   .OrderByDescending(x => x.Weight)
                   .ThenBy(x => Math.Abs(word.Length - x.Name.Length))
                   .ThenByDescending(x => char.IsUpper(x.Name[0]) == char.IsUpper(word[0]))
                   .Select(x => x.Name)
                   .ToList());
        }
示例#2
0
        /// <summary>Search for similar words in the collection</summary>
        /// <param name="Word">The word to search for</param>
        /// <param name="Collection">The collection to look in</param>
        /// <param name="MinSameLetters">The minimum number of matching letters, from the right end, min value - <see cref="DefaultMinSameLetters"/></param>
        public string GetSimilar(string Word, IEnumerable <string> Collection, int MinSameLetters = DefaultMinSameLetters)
        {
            if (MinSameLetters < DefaultMinSameLetters)
            {
                throw new ArgumentOutOfRangeException($"{nameof(MinSameLetters)} value can not be smaller than {DefaultMinSameLetters}!");
            }

            if (Word == null || Word.Length < MinSameLetters)
            {
                return(Word);
            }

            string foundWord = null;
            ConcurrentBag <SimilarCandidate> candidates = new ConcurrentBag <SimilarCandidate>();

            Parallel.ForEach(Collection, (str, loopState) =>
            {
                if (str == Word)
                {
                    foundWord = str;
                    loopState.Stop();
                    return;
                }

                int maxPosition = Math.Min(Word.Length, str.Length);
                int weight      = 0;

                for (int i = 1; i <= maxPosition; i++)
                {
                    if (str[str.Length - i] == Word[Word.Length - i])
                    {
                        int wi  = i - 1;
                        weight += wi < SameLetterWeights.Length ? SameLetterWeights[wi] : 1;
                    }
                    else if (i <= MinSameLetters)
                    {
                        return;
                    }
                }

                SimilarCandidate c = new SimilarCandidate()
                {
                    Name   = str,
                    Weight = weight
                };

                candidates.Add(c);
            });

            if (!string.IsNullOrEmpty(foundWord))
            {
                return(foundWord);
            }

            SimilarCandidate candidate = null;

            foreach (SimilarCandidate c in candidates)
            {
                if (candidate == null ||
                    c.Weight > candidate.Weight ||
                    (c.Weight == candidate.Weight && c.Name.Length < candidate.Name.Length) ||
                    (c.Weight == candidate.Weight && c.Name.Length == candidate.Name.Length && c.Name.CompareTo(candidate.Name) < 0))
                {
                    candidate = c;
                }
            }

            return(candidate?.Name);
        }
示例#3
0
        /// <summary>
        /// Ищет наиболее подходящее совпадение в коллекции для указанного слова.
        /// Сравнение символов начинается с конца слова, чем ближе символ к началу слова, тем меньше веса совпадение имеет.
        /// Пример: пара [краснЫй и краснОй] имеет меньший вес совпадения, чем пара [КРАСный и УСТный].
        /// </summary>
        /// <param name="word">Слово для поиска в коллекции.</param>
        /// <param name="collection">Коллекция, в которой искать совпадения.</param>
        /// <param name="minSameLetters">Минимальное кол-во совпадающих символов с конца слова.</param>
        /// <param name="maxSameLetters">
        /// Максимальное кол-во совпадающих символов с конца слова.
        /// Можно использовать <see cref="int.MaxValue"/> для сравнения всех символов слова.
        /// </param>
        public string GetSimilar(string word, IEnumerable <string> collection, int minSameLetters, int maxSameLetters)
        {
            if (word == null || word.Length < minSameLetters)
            {
                return(word);
            }

            string foundWord = null;
            List <SimilarCandidate> candidates = new List <SimilarCandidate>();

            foreach (string str in collection)
            {
                if (str == word)
                {
                    foundWord = str;
                    break;
                }

                int sameLetters;
                int maxPosition = Math.Min(maxSameLetters, Math.Min(word.Length, str.Length));
                int weight      = this.GetSimilarityWeight(word, str, maxPosition, minSameLetters, out sameLetters);

                if (sameLetters >= minSameLetters)
                {
                    SimilarCandidate c = new SimilarCandidate()
                    {
                        Name   = str,
                        Weight = weight
                    };

                    candidates.Add(c);
                }
            }

            if (!string.IsNullOrEmpty(foundWord))
            {
                return(foundWord);
            }

            SimilarCandidate candidate = null;

            foreach (SimilarCandidate c in candidates)
            {
                if (candidate == null)
                {
                    candidate = c;
                    continue;
                }

                if (c.Weight > candidate.Weight)
                {
                    candidate = c;
                    continue;
                }

                bool sameWeight       = c.Weight == candidate.Weight;
                int  betterLengthDiff = Math.Abs(word.Length - c.Name.Length) - Math.Abs(word.Length - candidate.Name.Length);

                if (sameWeight && betterLengthDiff < 0)
                {
                    candidate = c;
                    continue;
                }

                bool sameCase = char.IsUpper(c.Name[0]) == char.IsUpper(word[0]);

                if (sameWeight && betterLengthDiff == 0 && sameCase)
                {
                    candidate = c;
                    continue;
                }
            }

            return(candidate?.Name);
        }