如何使两个具有相同单词/含义但具有Unicode差异的字符串散列到相同的id



对于我正在进行的web抓取项目,我计划将实体存储在数据库中,其中实体的ID是其名称/标题的md5哈希。

然而,由于字符串中存在Unicode,相同名称/标题的不同哈希将出现

例如;运动学、物理教育和娱乐;将不同于";运动学、物理教育和娱乐";。

我尝试使用Unicode规范化,但哈希之间的差异仍然是相同的

import hashlib
import unicodedata

def generate_id(*args):
"""
:param args: strings to be used to generate an id
:return: md5 hash of the passed arguments
"""
string = ''
for arg in args:
string += ' ' + arg
hash_algorithm = hashlib.md5()
hash_algorithm.update(string.encode('utf-8'))
return hash_algorithm.hexdigest()

def clean_text(text):
"""
normalizes the unicode in a text to be more readable and generate a more accurate id from
:param text: string to be normalized
:return: normalized version of text
"""
return unicodedata.normalize('NFC', text)

print(generate_id(clean_text('Kinesiology, Phys Edxa0and Recreation'))) # hashes to acd21f3b094a77d1a2393a8daeac42d9
print(generate_id('Kinesiology, Phys Ed and Recreation')) # hashes to 5ac6bc3ca3d743d99e9b93a7a5379fe9

我该怎么做才能确保两个字符串相同并散列到相同的id,使得"Kinesiology,Phys Ed \xA0 and Recreation"与"Kinesiology,Phys Ed\xA0 and Recreation"是相同的字符串和散列(无论存在哪种unicode,任何2个字符串都相同(?

由于"具有相同的散列";只是二进制相等的代理,您需要的是将字符串规范化为相同。

在Unicode术语中,给定的两个字符串在规范上不等价,但它们是兼容的。因此,您将能够使用clean_text()函数中的兼容性分解/组合范式(NFKDNFKC(生成相同的哈希:

def clean_text(text):
return unicodedata.normalize('NFKD', text)

NO-BREAK SPACE (U+00A0)字符的分解特性被设置为<noBreak> SPACE (U+0020)。事实上,分解属性中存在一个关键字(在本例中为<noBreak>(,这表明该字符与正则空间字符兼容,但在规范上不等价。


旁注

因为它是在评论中要求的,所以对NFKC和NFKD范式之间的区别进行了一点澄清:

Unicode字符可以由多个代码点组成。某些字符可以用不同的方式(但在规范上等效(表示:要么作为单个代码点,要么作为代码点的组合。例如:é可以表示为ée + ◌́。当标准化时,合成正规形式(NFC,NFKC(将尝试将序列转换为其合成形式(e + ◌́é(;分解范式(NFD,NFKD(将尝试将组合字符转换为序列(ée + ◌́(。你使用哪一个完全取决于情况。只是要确保不要把苹果比作桔子。

最新更新