我需要比较字符串以决定它们是否代表相同的东西。这涉及人类输入的案例标题,其中缩写和其他小细节可能不同。例如,请考虑以下两个标题:
std::string first = "Henry C. Harper v. The Law Offices of Huey & Luey, LLP";
相反:
std::string second = "Harper v. The Law Offices of Huey & Luey, LLP";
人类可以快速判断这些很可能是同一个。我采用的当前方法是通过降低所有字母的小写并删除所有标点符号和空格来规范化字符串:
std::string firstNormalized = "henrycharpervthelawofficesofhueylueyllp";
和
std::string secondNormalized = "harpervthelawofficesofhueylueyllp";
在这种情况下,一个是另一个的子序列,但是您可以想象其他更复杂的变体,其中不一定会发生,但它们具有共同的重要子序列。也可能偶尔出现人为输入错误,例如转置字母和拼写错误。
也许某种角色差异程序可以帮助?我已经看到用于比较要检入的代码差异的良好行差异程序,在字符的基础上有类似的东西,也许在提升?如果你可以统计连续字符的数量并将比率与非共享字符进行比较,那么这可能是一个很好的启发式算法?
最后,我需要一个布尔决定,是否将它们视为相同或不相同。它不一定是完美的,但理想情况下应该很少是错误的。
我可以使用哪种算法来量化这两个字符串彼此之间的相似程度,然后我可以通过某种启发式将其转换为是/否答案?
答案 0 :(得分:71)
您正在寻找的是String Metric算法。其中有重要个数,其中许多具有相似的特征。其中比较受欢迎:
在这个主题的wiki page上查看这些以及其他人。
答案 1 :(得分:10)
Damerau Levenshtein distance是另一种比较两个字符串的算法,它类似于Levenshtein距离算法。两者之间的区别在于它还可以检查字符之间的转置,因此可以为纠错提供更好的结果。
例如:night
和nigth
之间的Levenshtein距离为2
但是night
和nigth
之间的Damerau Levenshtein距离将为1,因为它只是一对角色的交换。
答案 2 :(得分:3)
你可以使用ngrams。例如,在单词三元组(通常是小写)中转换两个字符串,并比较它们彼此相等的百分比。
您面临的挑战是确定相似性的最小百分比。
答案 3 :(得分:1)
您可以考虑的另一种算法是西蒙·怀特相似度:
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
答案 4 :(得分:0)
您可以使用计算最长公共子序列长度的算法来解决该问题。如果两个输入字符串的最长公共子序列的长度小于两个字符串中任何一个的长度,则它们不相等。
如果您不想弄清楚最长的公共子序列,也可以使用动态编程的方法来解决问题并优化空间复杂度。