我正在使用Python编写拼写检查程序。我有一个有效单词列表(字典),我需要从这个字典中输出一个单词列表,它与给定的无效单词的编辑距离为2。
我知道我需要从无效单词生成一个编辑距离为1的列表开始(然后再对所有生成的单词再次运行)。我有三个方法,插入(...),删除(...)和更改(...)应输出编辑距离为1的单词列表,其中插入输出所有有效单词多于一个字母的单词给定的单词,删除输出所有有效单词少一个字母的单词,并且更改输出所有有效单词和一个不同的单词。
我检查了很多地方,但我似乎找不到描述这个过程的算法。我提出的所有想法都涉及多次遍历字典列表,这将非常耗时。如果有人能提供一些见解,我将非常感激。
答案 0 :(得分:46)
您正在查看的内容称为编辑距离,此处为nice explanation on wiki。有很多方法可以定义两个单词之间的距离,你想要的那个被称为Levenshtein距离,这里是python中的DP实现。
def levenshteinDistance(s1, s2):
if len(s1) > len(s2):
s1, s2 = s2, s1
distances = range(len(s1) + 1)
for i2, c2 in enumerate(s2):
distances_ = [i2+1]
for i1, c1 in enumerate(s1):
if c1 == c2:
distances_.append(distances[i1])
else:
distances_.append(1 + min((distances[i1], distances[i1 + 1], distances_[-1])))
distances = distances_
return distances[-1]
答案 1 :(得分:10)
这是Levenshtein距离的版本
def edit_distance(s1, s2): m=len(s1)+1 n=len(s2)+1 tbl = {} for i in range(m): tbl[i,0]=i for j in range(n): tbl[0,j]=j for i in range(1, m): for j in range(1, n): cost = 0 if s1[i-1] == s2[j-1] else 1 tbl[i,j] = min(tbl[i, j-1]+1, tbl[i-1, j]+1, tbl[i-1, j-1]+cost) return tbl[i,j] print(edit_distance("Helloworld", "HalloWorld"))
答案 2 :(得分:7)
#this calculates edit distance not levenstein edit distance
word1="rice"
word2="ice"
len_1=len(word1)
len_2=len(word2)
x =[[0]*(len_2+1) for _ in range(len_1+1)]#the matrix whose last element ->edit distance
for i in range(0,len_1+1): #initialization of base case values
x[i][0]=i
for j in range(0,len_2+1):
x[0][j]=j
for i in range (1,len_1+1):
for j in range(1,len_2+1):
if word1[i-1]==word2[j-1]:
x[i][j] = x[i-1][j-1]
else :
x[i][j]= min(x[i][j-1],x[i-1][j],x[i-1][j-1])+1
print x[i][j]
答案 3 :(得分:1)
您描述的特定算法称为Levenshtein距离。一个快速的Google会抛出几个Python库和配方来计算它。
答案 4 :(得分:1)
此任务需要最小编辑距离。
以下是我对MED的Levenshtein距离的版本。
def MED_character(str1,str2):
cost=0
len1=len(str1)
len2=len(str2)
#output the length of other string in case the length of any of the string is zero
if len1==0:
return len2
if len2==0:
return len1
accumulator = [[0 for x in range(len2)] for y in range(len1)] #initializing a zero matrix
# initializing the base cases
for i in range(0,len1):
accumulator[i][0] = i;
for i in range(0,len2):
accumulator[0][i] = i;
# we take the accumulator and iterate through it row by row.
for i in range(1,len1):
char1=str1[i]
for j in range(1,len2):
char2=str2[j]
cost1=0
if char1!=char2:
cost1=2 #cost for substitution
accumulator[i][j]=min(accumulator[i-1][j]+1, accumulator[i][j-1]+1, accumulator[i-1][j-1] + cost1 )
cost=accumulator[len1-1][len2-1]
return cost
答案 5 :(得分:1)
difflib
具有各种用于序列匹配的实用程序,包括可以使用的get_close_matches
方法。它使用从Ratcliff和Obershelp改编的算法。
来自文档
from difflib import get_close_matches
# Yields ['apple', 'ape']
get_close_matches('appel', ['ape', 'apple', 'peach', 'puppy'])
答案 6 :(得分:0)
使用 BK树或 TRIE 而不是使用Levenshtein距离算法,因为这些算法的复杂性较低,然后编辑距离。对这些主题的一个很好的浏览将给出详细的描述。
此link可以为您提供有关拼写检查的更多信息。
答案 7 :(得分:0)
使用Python内置的difflib
中的SequenceMatcher
是另一种方法。奖励:它支持忽略“垃圾”部分(例如空格或标点符号)。
from difflib import SequenceMatcher
a = 'kitten'
b = 'sitting'
required_edits = [
code
for code in (
SequenceMatcher(a=a, b=b, autojunk=False)
.get_opcodes()
)
if code[0] != 'equal'
]
required_edits
# [
# # (tag, i1, i2, j1, j2)
# ('replace', 0, 1, 0, 1), # replace a[0:1]="k" with b[0:1]="s"
# ('replace', 4, 5, 4, 5), # replace a[4:5]="e" with b[4:5]="i"
# ('insert', 6, 6, 6, 7), # insert b[6:7]="g" after a[6:6]="n"
# ]
# the edit distance:
len(required_edits) # == 3
答案 8 :(得分:0)
类似于上述Santoshi的解决方案,但我进行了三处更改:
from itertools import product
def edit_distance(s1,s2):
d={ **{(i,0):i for i in range(len(s1)+1)},**{(0,j):j for i in range(len(s2)+1)}}
for i, j in product(range(1,len(s1)+1), range(1,len(s2)+1)):
d[i,j]=min(int(s[i-1]!=s[j-1]) + d[i-1,j-1], d[i-1,j]+1, d[i,j-1]+1)
return d[i,j]