perlは写経でいまいち理解度があやしいため、pythonでBoyer-Moore法を。パターンとの不一致の場合には何文字スキップできるか、一致した場合に何文字スキップできるかのテーブルを最初に作っておいて、スキップ幅の大きいほうでスキップしながらパターンマッチを進めていく。
def boyer_moore_bad_character (P):
m = len(P)
bc = [m] * 256
j = m
for char in list(P):
bc[ord(char)] = j - 1
j -= 1
return m, bc
def boyer_moore_good_suffix (m,P):
j = m + 1
gs = [0] * j
k = [0] * j
k[m] = j
for i in reversed(range(1,j)):
while j <= m and P[i-1] != P[j-1]:
if gs[j] == 0:
gs[j] = j - i
j = k[j]
j -= 1
k[i-1] = j
kn = k[0]
for j in range(m+1):
if gs[j] == 0: gs[j] = kn
if j == kn: kn = k[kn]
gs.pop(0)
return gs
def boyer_moore (T,P):
(m,bc) = boyer_moore_bad_character(P)
gs = boyer_moore_good_suffix(m,P)
(i, last_i, first_j) = (0, len(T)-m, m-1)
for i in range(last_i+1):
j = first_j
while j >= 0 and T[i+j] == P[j]:
j -= 1
if j < 0:
return i
else:
bcn = bc[ord(T[i+j])] - m + j + 1
gsn = gs[j]
i += bcn if bcn > gsn else gsn
return -1
if __name__ == '__main__':
print boyer_moore("perlpypythonruby","python")
- pythonはコードの見通しがよいですな
- perlと違ってsubstrとかやらなくてもいいので見通しがよい
- perlのshiftがpop(0)なのがあれ。先頭をpopするってのが。
- perlだと$a[5]=5とやれるけど、pythonはそれ以前の要素が自動的ににundefで埋まらない
for文でカウンタ変数使いたかったのでrangeをつかったけどPython流はどうやるのがよろしいんだろうか、、、カウンタ変数減算するのにfor i in reversed(range(1,j))だしな。