J'ai besoin de comparer des chaînes pour décider si elles représentent la même chose. Cela concerne les titres de cas saisis par les humains où les abréviations et autres petits détails peuvent différer. Par exemple, considérez les deux titres suivants:
std::string first = "Henry C. Harper v. The Law Offices of Huey & Luey, LLP";
Par opposition à:
std::string second = "Harper v. The Law Offices of Huey & Luey, LLP";
Un être humain peut rapidement évaluer que ce sont probablement les mêmes. L'approche que j'ai adoptée actuellement est de normaliser les chaînes en minuscules toutes les lettres et en supprimant toute ponctuation et les espaces donnant:
std::string firstNormalized = "henrycharpervthelawofficesofhueylueyllp";
Et:
std::string secondNormalized = "harpervthelawofficesofhueylueyllp";
En comparant dans ce cas, l'une est une sous-séquence de l'autre, mais vous pouvez imaginer d'autres variations plus complexes où cela ne se produit pas nécessairement, mais elles ont en commun des sous-séquences importantes. Il peut également y avoir des erreurs de saisie humaine occasionnelles telles que des lettres transposées et des fautes d'orthographe.
Peut-être qu'une sorte de programme de diff de caractères pourrait aider? J'ai vu de bons programmes de comparaison de ligne pour comparer les différences de code à enregistrer, y a-t-il quelque chose comme ça sur une base de caractères, peut-être en boost? Si vous pouviez compter le nombre de caractères consécutifs en commun et prendre le rapport aux caractères non partagés, ce serait peut-être une bonne heuristique?
En fin de compte, j'ai besoin d'une décision booléenne pour les considérer comme identiques ou non. Il ne doit pas être parfait, mais il devrait idéalement rarement se tromper.
Quel algorithme puis-je utiliser qui me donnera une sorte de quantification de la similitude des deux chaînes que je pourrai ensuite convertir en réponse oui/non au moyen d'une heuristique?
Ce que vous recherchez s'appelle String Metric algorithmes. Il y en a significatif nombre d'entre eux, beaucoup avec des caractéristiques similaires. Parmi les plus populaires:
Jetez un œil à ceux-ci ainsi qu'à d'autres sur la page wiki sur le sujet.
Damerau Levenshtein distance est un autre algorithme pour comparer deux chaînes et il est similaire à l'algorithme de distance de Levenshtein. La différence entre les deux est qu'il peut également vérifier les transpositions entre les caractères et donc donner un meilleur résultat pour la correction d'erreur.
Par exemple: la distance de Levenshtein entre night
et nigth
est de 2 mais la distance de Damerau Levenshtein entre night
et nigth
sera de 1 car il s'agit simplement d'un échange de une paire de personnages.
Vous pouvez utiliser des ngrams pour cela. Par exemple, transformez les deux chaînes en trigrammes Word (généralement en minuscules) et comparez le pourcentage d'entre elles qui sont égales l'une à l'autre.
Votre défi est de définir un pourcentage minimum de similitude.
Un autre algorithme que vous pouvez considérer est la similitude de Simon White:
def get_bigrams(string):
"""
Take a string and return a list of bigrams.
"""
if string is None:
return ""
s = string.lower()
return [s[i : i + 2] for i in list(range(len(s) - 1))]
def simon_similarity(str1, str2):
"""
Perform bigram comparison between two strings
and return a percentage match in decimal form.
"""
pairs1 = get_bigrams(str1)
pairs2 = get_bigrams(str2)
union = len(pairs1) + len(pairs2)
if union == 0 or union is None:
return 0
hit_count = 0
for x in pairs1:
for y in pairs2:
if x == y:
hit_count += 1
break
return (2.0 * hit_count) / union
Vous pouvez utiliser l'algorithme de calcul de la longueur de la sous-séquence commune la plus longue pour résoudre le problème. Si la longueur de la sous-séquence commune la plus longue pour les deux chaînes d'entrée est inférieure à la longueur de l'une ou l'autre des chaînes, elles sont inégales.
Vous pouvez utiliser l'approche de la programmation dynamique pour résoudre le problème et optimiser la complexité de l'espace au cas où vous ne souhaitez pas déterminer la sous-séquence commune la plus longue.