因为选修了搜索引擎的课程,最近在做传统的字符串检索匹配实验。我在网上找了很久的Python的源代码,有些是返回的结果不是我想要的,有些则是完全不能运行。所以我在这里整理了我的学习过程。下面我会贴出一些比较好的算法教程链接以及Python实现。
BF算法
BF(Brute Force)算法就是朴素的暴力匹配。BF算法的基本思想是从主串的start位置开始与模式串进行匹配,如果相等,则继续比较后续字符,如果不相等则模式串回溯到开始位置,主串回溯到start+1位置,继续进行比较直至模式串的所有字符都已比较成功,则匹配成功,或者主串所有的字符已经比较完毕,没有找到完全匹配的字串,则匹配失败。
Python实现:
def BF(s, p):
""" 蛮力法字符串匹配 """
indies = []
n = len(s)
m = len(p)
for i in range(n - m + 1):
index = i
for j in range(m):
if s[index] == p[j]:
index += 1
else:
break
if index - i == m:
indies.append(i)
return indies
KMP算法
KMP(Knuth-Morris-Pratt)匹配算法是对BF算法的改进。具体过程就是计算一张“部分匹配表”来改进移动距离。网上有很多教程,我这里给大家推荐阮一峰老师的教程,写的非常通俗易懂。
Python实现:
def getNextList(s):
n = len(s)
nextList = [0, 0]
j = 0
for i in range(1, n):
while j > 0 and s[i] != s[j]:
j = nextList[j]
if s[i] == s[j]:
j += 1
nextList.append(j)
return nextList
def KMP(s, p):
""" Knuth-Morris-Pratt算法实现字符串查找 """
n = len(s)
m = len(p)
nextList = getNextList(p)
indies = []
j = 0
for i in range(n):
while s[i] != p[j] and j > 0:
j = nextList[j]
if s[i] == p[j]:
j += 1
if j == m:
indies.append(i-m+1)
j = nextList[j]
return indies
BM算法
BM(Boyer-Moore)算法是对KMP进一步的改进。总体来说BM算法效率是高于KMP算法的,文本量越大BM算法的效果越明显。BM算法通过两张表来改进移动的距离。我在这里还是给大家推荐阮一峰老师的教程。
Python实现:
def getBMBC(pattern):
# 预生成坏字符表
BMBC = dict()
for i in range(len(pattern) - 1):
char = pattern[i]
# 记录坏字符最右位置(不包括模式串最右侧字符)
BMBC[char] = i + 1
return BMBC
def getBMGS(pattern):
# 预生成好后缀表
BMGS = dict()
# 无后缀仅根据坏字移位符规则
BMGS[''] = 0
for i in range(len(pattern)):
# 好后缀
GS = pattern[len(pattern) - i - 1:]
for j in range(len(pattern) - i - 1):
# 匹配部分
NGS = pattern[j:j + i + 1]
# 记录模式串中好后缀最靠右位置(除结尾处)
if GS == NGS:
BMGS[GS] = len(pattern) - j - i - 1
return BMGS
def BM(string, pattern):
""" Boyer-Moore算法实现字符串查找 """
m = len(pattern)
n = len(string)
i = 0
j = m
indies = []
BMBC = getBMBC(pattern=pattern) # 坏字符表
BMGS = getBMGS(pattern=pattern) # 好后缀表
while i < n:
while (j > 0):
if i + j -1 >= n: # 当无法继续向下搜索就返回值
return indies
# 主串判断匹配部分
a = string[i + j - 1:i + m]
# 模式串判断匹配部分
b = pattern[j - 1:]
# 当前位匹配成功则继续匹配
if a == b:
j = j - 1
# 当前位匹配失败根据规则移位
else:
i = i + max(BMGS.setdefault(b[1:], m), j - BMBC.setdefault(string[i + j - 1], 0))
j = m
# 匹配成功返回匹配位置
if j == 0:
indies.append(i)
i += 1
j = len(pattern)