一、ECDICT简介
ECDICT是一个免费开源的中英词典数据库,收录了数十万条单词。如果想让桌面小部件在离线状态下方便简介的查询单词,使用自带的词库无疑是最佳选择。
ECDICT提供了Python的编程接口,可以方便快速的查询单词。此外,ECDICT也提供了单词的词性变化、标签(四六级)等信息,具体可以去github上寻找项目浏览README.md文档。
由于编程接口的存在,其使用也异常简单,这里以类DictCsv为例:
def loadWordVisitor(self):
self.par.isLoading = True
self.par.wordVisitor = DictCsv('ecdict.csv')
self.par.vocab = set(words.words())
self.par.isLoading = False
注意这里真正有关ECDICT的代码只有第三行,创建一个单词管理器。之所以有其他内容,是因为加载数据库较为耗时,需要放在线程中避免阻塞应用运行,同时在加载期间设置加载标签为True,用于禁止用户的查询操作。vocab用于模糊匹配单词,后面会讲到。
def query(self):
# 检查是否有加载操作正在进行,如果有,则不执行查询
if self.par.isLoading or self.par.isMatchingWord:
return
# 获取线编辑框中的文本内容
self.text = self.lineeditQuery.text()
# 更新界面中的单词显示区域的文本
self.showWord.text = self.text
# 使用查询的文本,将结果设置到单词显示逻辑中
self.showWord.setWordLogic(self.par.wordVisitor.query(self.text))
# 确保单词显示区域可见
self.showWord.show()
使用时只需要调用DictCsv类实例的query方法,便能查询相应单词,返回一个字典,包含单词序号、汉译、词性变换等众多信息。
二、模糊匹配
ECDICT提供了模糊匹配单词的功能,但貌似只能匹配开头字母一致的一系列单词,应该是为了防止用户查询时单词形态出现问题。笔者希望能进一步完善这一功能,比如即便用户输入pronouncation,桌面部件也能给出正确的pronunciation。
为了实现这一目标,这里使用了nltk库,nltk库提供了edit_distance方法计算两个字符串之间的相似度,同时提供了一个英语词库(即上文的vocab,仅有单词,没有其它冗余元素),由于用户输入的不确定性,在直接查询失败时,最好是逐一计算相似度取最大值,经实测,匹配一个单词需要十数秒,这显然是无法接受的。但是如果采取一些前置条件:
def matchWord(self, word):
self.par.isMatchingWord = True
# 初始化最小编辑距离和当前单词
minDistance = edit_distance('natsuki', word) # 默认初始化为 'nasuki' 到输入单词的距离
current_word = ''
# 遍历词汇表以找到与输入单词编辑距离最小的单词
for w in self.par.vocab:
# 如果单词长度差异大于等于3,则跳过
if abs(len(word) - len(w)) >= 3:
continue
# 单词长度大于等于2时,检查首字母或次字母是否匹配
if len(w) >= 2 and len(word) >= 2:
if word[0] != w[0] and word[1] != w[0]:
continue
# 单词长度大于等于4时,检查末字母或倒数第二字母是否匹配
if len(w) >= 4 and len(word) >= 4:
if word[-1] != w[-1] and word[-2] != w[-2]:
continue
# 计算当前单词与输入单词的编辑距离
distance = edit_distance(word, w)
# 如果当前距离小于最小距离,更新最小距离和当前单词
if distance < minDistance:
minDistance = distance
current_word = w
# 如果当前单词不为空,写入推测结果,询问用户是否是指定的单词
if current_word != '':
self.writeOutput(f'你想找的是不是 <span style="color: #00ff00;">{current_word}</span>?')
# 调用逻辑处理函数,传递当前单词的查询结果
self.setWordLogic(self.par.wordVisitor.query(current_word), True)
self.par.isMatchingWord = False
通过默认用户希望匹配的单词与输入差异小于3以及首尾两字母是否大致对应,可以将延迟减少到用户难以察觉的程度。