свободный поиск строки в массиве с помощью С#

скажем, у нас есть

string[] array = {"telekinesis", "laureate", "Allequalsfive", "Indulgence"};

и нам нужно найти слово в этом массиве

обычно мы делаем следующее: (или используем любой подобный метод для поиска строки)

bool result = array.Contains("laureate"); // returns true

В моем случае слово, которое я ищу, может содержать ошибки (как следует из названия).

Например, я не могу различить буквы «I» (большая «i») и «l» (маленькая «L») и «1» (цифра один).

Можно ли как-нибудь найти такое слово, как "Allequalsfive", "A11equalsfive" или "AIIequalsfive"? (свободный поиск) Обычно результат будет "false".

Если бы я только мог указать игнорировать некоторые буквы... (последовательность постоянна, остальные буквы постоянны).


person Alex    schedule 06.04.2012    source источник
comment
хорошей областью для изучения будет алгоритм расстояния Левенштейна, часто используемый в программах проверки орфографии en.wikipedia.org/ вики/Levenshtein_distance   -  person krystan honour    schedule 06.04.2012


Ответы (3)


С помощью методов расширения и алгоритма Расстояние Левенштейна

var array = new string[]{ "telekinesis", "laureate", 
                          "Allequalsfive", "Indulgence" };

bool b = array.LooseContains("A11equalsfive", 2); //returns true

-

public static class UsefulExtensions
{
    public static bool LooseContains(this IEnumerable<string> list, string word,int distance)
    {
        foreach (var s in list)
            if (s.LevenshteinDistance(word) <= distance) return true;
        return false;
    }

    //
    //http://www.merriampark.com/ldcsharp.htm
    //
    public static int LevenshteinDistance(this string s, string t)
    {
        int n = s.Length;
        int m = t.Length;
        int[,] d = new int[n + 1, m + 1];

        // Step 1
        if (n == 0)
            return m;

        if (m == 0)
            return n;

        // Step 2
        for (int i = 0; i <= n; d[i, 0] = i++){}

        for (int j = 0; j <= m; d[0, j] = j++){}

        // Step 3
        for (int i = 1; i <= n; i++)
        {
            //Step 4
            for (int j = 1; j <= m; j++)
            {
                // Step 5
                int cost = (char.ToUpperInvariant(t[j - 1]) == char.ToUpperInvariant(s[i - 1])) ? 0 : 1;

                // Step 6
                d[i, j] = Math.Min(
                    Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1),
                    d[i - 1, j - 1] + cost);
            }
        }
        // Step 7
        return d[n, m];
    }
}
person L.B    schedule 06.04.2012

Вы можете использовать перегрузку Contains, которая принимает IEqualityComparer<TSource>.

Реализуйте свой собственный компаратор равенства, который игнорирует буквы, которые вы хотите, и вперед.

person Oded    schedule 06.04.2012

если вам нужно только знать, свободно ли слово содержится в вашем массиве, вы можете просто «очистить» буквы, которые хотите игнорировать (например, заменить «1» на «l») как в вашем слове поиска, так и в массиве:

Func<string, string> clean = x => x.ToLower().Replace('1', 'l');
var array = (new string[] { "telekinesis", "laureate", "A11equalsfive", "Indulgence" }).Select(x => clean(x));          
bool result = array.Contains(clean("allequalsfive"));

В противном случае вы можете найти ключевое слово Where() LINQ, которое позволяет фильтровать массив на основе указанной вами функции.

person Lâm Tran Duy    schedule 06.04.2012