常规的正则及匹配等这里不赘述
看下比较高级的算法
一、KMP 算法
暴力匹配
暴力匹配方法的思想非常朴素:
依次从主串的首字符开始,与模式串逐一进行匹配;
遇到失配时,则移到主串的第二个字符,将其与模式串首字符比较,逐一进行匹配;
重复上述步骤,直至能匹配上,或剩下主串的长度不足以进行匹配。
参考代码如下:
def brute_force_match(t,p):
tlen=len(t)
plen=len(p)
for i in range(tlen):
j=0
while t[i+j]==p[j] and j <plen:
j=j+1
if j==plen:
return i
return -1
算法复杂度分析:i 在主串上移动 (n-p)次,匹配失败时,j 移动次数最多有 p-1 次。因此复杂度为 O(n*p)。
对于暴力匹配而言,就存在重复匹配的现象。比如,第一次匹配失败时,主串,模式串失败匹配的位置的字符分别为 a 与 c ,下一次匹配时主串,模式串的起始位置分别为 T[1] 与 P[0];而在模式串中 c 之前是 ab ,未有重复结构,因此 T[1]与 P[0]肯定不能匹配上,这样造成了重复匹配。直观上,下一次匹配应从 T[2] 与 P[0] 开始。
那么如何提高匹配效率呢?那就考虑下 KMP 算法。
KMP 详细证明
KMP 算法思想归纳如下:将主串 T 的第一个字符与模式串 P 的第一个字符进行匹配。如果相等,则依次比较 T 和 P 的下一个字符。如果不相等,则 主串 T 移动(已匹配字符数-对应的部分匹配值)位,继续匹配。
关于移动位数的解释:已匹配字符数,即当前已完成匹配的字符数量。部分匹配值就是前缀和后缀的最长的共有元素的长度。
前缀指除了最后一个字符以外,一个字符串的全部头部组合。
后缀指除了第一个字符以外,一个字符串的全部尾部组合。
举个例子:以"ABCDABD"为例
"A"的前缀和后缀都为空集,共有元素的长度为 0;
"AB"的前缀为[A],后缀为[B],共有元素的长度为 0;
"ABC"的前缀为[A, AB],后缀为[BC, C],共有元素的长度 0;
"ABCD"的前缀为[A, AB, ABC],后缀为[BCD, CD, D],共有元素的长度为 0;
"ABCDA"的前缀为[A, AB, ABC, ABCD],后缀为[BCDA, CDA, DA, A],共有元素为"A",长度为 1;
"ABCDAB"的前缀为[A, AB, ABC, ABCD, ABCDA],后缀为[BCDAB, CDAB, DAB, AB, B],共有元素为"AB"