Подтвердить что ты не робот

Строковые алгоритмы подобия?

Мне нужно сравнить 2 строки и рассчитать их подобие, отфильтровать список наиболее похожих строк.

Eg. поиск "собаки" вернет

  • собака
  • прокл`ятый
  • болотный
  • туман
  • туманный

Eg. поиск "трещины" вернет

  • трещина
  • острить
  • стойки
  • домкрат
  • шарлатан

Я столкнулся:

Знаете ли вы о каких-либо строковых алгоритмах сходства?

4b9b3361

Ответ 1

Кажется, вам нужно какое-то нечеткое совпадение. Вот java-реализация некоторого набора показателей подобия http://www.dcs.shef.ac.uk/~sam/stringmetrics.html. Вот подробное объяснение строковых метрик http://www.cs.cmu.edu/~wcohen/postscript/ijcai-ws-2003.pdf, это зависит от того, насколько нечеткой и насколько быстро ваша реализация должна быть.

Ответ 2

Levenshtein расстояние - это алгоритм, который я бы рекомендовал. Он вычисляет минимальное количество операций, которые вы должны выполнить, чтобы изменить одну строку на другую. Чем меньше изменений означает, что строки более похожи...

Ответ 3

Если основное внимание уделяется производительности, я бы выполнил алгоритм, основанный на структуре trie
(хорошо работает, чтобы найти слова в тексте или помочь исправить слово, но в вашем случае вы можете быстро найти все слова, содержащие заданное слово или все, кроме одной буквы).

Пожалуйста, сначала следуйте ссылке wikipedia выше. Tries - это самый быстрый метод сортировки слов (n слов, поиск s, O (n) для создания trie, O (1) для поиска s (или, если хотите, если a - средняя длина, O (an) для trie и O (s) для поиска)).

Быстрая и простая реализация (для оптимизации) вашей проблемы (похожие слова) состоит из

  • Сделайте trie со списком слов, имея все буквы, индексированные спереди и сзади (см. пример ниже)
  • Для поиска s, итерации с s [0], чтобы найти слово в trie, затем s [1] и т.д.
  • В trie, если количество найденных букв равно len (s) -k, отображается слово, где k - допуск (1 письмо отсутствует, 2...).
  • Алгоритм может быть расширен до слов в списке (см. ниже)

Пример: со словами car, vars.

Построение trie (большая буква означает, что слово заканчивается здесь, а другое может продолжаться). > - это пост-индекс (вперед), а < - предварительный индекс (возврат назад). В другом примере нам может потребоваться указать также начальное письмо, оно не представлено здесь для ясности.
< и > в С++, например, были бы Mystruct *previous,*next, что означает a > c < r, вы можете перейти непосредственно от a в c и обратно, также от a до R.

  1.  c < a < R
  2.  a > c < R
  3.    > v < r < S
  4.  R > a > c
  5.        > v < S
  6.  v < a < r < S
  7.  S > r > a > v

Глядя строго на автомобиль, trie дает вам доступ от 1., и вы найдете автомобиль (вы бы нашли также все, начиная с автомобиля, но и с машиной внутри - это не в примере), но викарий, например, были найдены из c > i > v < a < R).

Чтобы выполнить поиск, разрешая 1-буквенный неправильный/отсутствующий допуск, вы повторяете каждую букву s и подсчитываете количество последовательных - или пропуская 1 буквенные буквы, которые вы получаете от s в trie.

ищет car,

  • c: поиск trie для c < a и c < r (отсутствующая буква в s). Чтобы принять неправильную букву в слове w, попробуйте перепрыгнуть на каждую итерацию неправильную букву, чтобы увидеть, находится ли ar, это O (w). С двумя буквами O (w²) и т.д.... но еще один уровень индекса может быть добавлен в trie, чтобы принять во внимание прыжок по буквам - сделать сложный комплекс и жадным относительно памяти.
  • a, затем R: то же, что и выше, но и поиск назад

Это просто для того, чтобы представить идею о принципе: пример выше может иметь некоторые сбои (завтра я проверю).

Ответ 4

Вы можете сделать это:

Foreach string in haystack Do
    offset := -1;
    matchedCharacters := 0;
    Foreach char in needle Do
        offset := PositionInString(string, char, offset+1);
        If offset = -1 Then
            Break;
        End;
        matchedCharacters := matchedCharacters + 1;
    End;
    If matchedCharacters > 0 Then
       // (partial) match found
    End;
End;

С помощью сопоставленных символов вы можете определить "степень" матча. Если он равен длине иглы, все символы в игле также находятся в строке. Если вы также сохраняете смещение первого совпадающего символа, вы также можете сортировать результат по "плотности" совпадающих символов путем вычитания смещения первого совпадающего символа из смещения последнего совпадающего смещения символа; чем ниже разница, тем плотное совпадение.

Ответ 5

class Program
{ 

static 
 int ComputeLevenshteinDistance(string source, string target){
if ((source == null) || (target == null)) return 0;
if ((source.Length == 0) || (target.Length == 0)) return 0;
if (source == target) return source.Length;

int sourceWordCount = source.Length;
int targetWordCount = target.Length;

int[,] distance = new int[sourceWordCount + 1, targetWordCount + 1];

// Step 2
for (int i = 0; i <= sourceWordCount; distance[i, 0] = i++);
for (int j = 0; j <= targetWordCount; distance[0, j] = j++);

for (int i = 1; i <= sourceWordCount; i++)
{
    for (int j = 1; j <= targetWordCount; j++)
    {
        // Step 3
        int cost = (target[j - 1] == source[i - 1]) ? 0 : 1;

        // Step 4
        distance[i, j] = Math.Min(Math.Min(distance[i - 1, j] + 1, distance[i, j - 1] + 1), distance[i - 1, j - 1] + cost);
    }
}

return distance[sourceWordCount, targetWordCount]; 
}

 static void Main(string[] args){ Console.WriteLine(ComputeLevenshteinDistance ("Stackoverflow","StuckOverflow"));
Console.ReadKey();
}
}