02_string_search.hsp

sample\algorithms\02_string_search.hsp » Plain Format

;============================================================
;  アルゴリズム 06〜10: 文字列検索
;    06. 愚直 find (Naive)
;    07. KMP 文字列検索
;    08. Boyer-Moore (bad char)
;    09. Rabin-Karp (rolling hash)
;    10. StrRev (reverse string - bonus)
;============================================================

#include "hsp3cl_net_64.as"

; ----- 06. Naive -----
#module
#defcfunc naive_find var _hay, var _pat, \
	local _n, local _m, local _i, local _j, local _match
	_n = strlen(_hay) : _m = strlen(_pat)
	if _m == 0 : return 0
	repeat _n - _m + 1
		_i = cnt
		_match = 1
		repeat _m
			_j = cnt
			if peek(_hay, _i + _j) != peek(_pat, _j) : _match = 0 : break
		loop
		if _match : return _i
	loop
	return -1
#global

; ----- 07. KMP -----
#module
#defcfunc kmp_find var _hay, var _pat, \
	local _n, local _m, local _i, local _j
	_n = strlen(_hay) : _m = strlen(_pat)
	if _m == 0 : return 0
	if _m > _n : return -1
	dim lps, _m
	_j = 0
	repeat _m - 1
		_i = cnt + 1
		repeat
			if _j <= 0 : break
			if peek(_pat, _i) == peek(_pat, _j) : break
			_j = lps(_j - 1)
		loop
		if peek(_pat, _i) == peek(_pat, _j) : _j++
		lps(_i) = _j
	loop
	_i = 0 : _j = 0
	repeat
		if _i >= _n : return -1
		if peek(_hay, _i) == peek(_pat, _j) {
			_i++ : _j++
			if _j == _m : return _i - _j
		} else {
			if _j > 0 : _j = lps(_j - 1) : else : _i++
		}
	loop
#global

; ----- 08. Boyer-Moore (bad char) -----
#module
#defcfunc bm_find var _hay, var _pat, \
	local _n, local _m, local _i, local _j, local _shift, local _c, local _found
	_n = strlen(_hay) : _m = strlen(_pat)
	if _m == 0 : return 0
	if _m > _n : return -1
	dim _bad, 256
	repeat 256 : _bad(cnt) = -1 : loop
	repeat _m : _bad(peek(_pat, cnt)) = cnt : loop
	_i = 0
	repeat
		if _i > _n - _m : return -1
		_j = _m - 1
		_found = 1
		repeat
			if _j < 0 : break
			if peek(_pat, _j) != peek(_hay, _i + _j) : _found = 0 : break
			_j--
		loop
		if _found : return _i
		_c = peek(_hay, _i + _j)
		_shift = _j - _bad(_c)
		if _shift < 1 : _shift = 1
		_i += _shift
	loop
#global

; ----- 09. Rabin-Karp -----
#module
#defcfunc rabin_karp var _hay, var _pat, \
	local _n, local _m, local _i, local _h, local _ph, local _hh, local _BASE, local _MOD, \
	local _ok
	_BASE = 131 : _MOD = 2147483647
	_n = strlen(_hay) : _m = strlen(_pat)
	if _m == 0 : return 0
	if _m > _n : return -1
	_ph = 0 : _hh = 0 : _h = 1
	repeat _m - 1 : _h = _h * _BASE \ _MOD : loop
	repeat _m
		_ph = (_ph * _BASE + peek(_pat, cnt)) \ _MOD
		_hh = (_hh * _BASE + peek(_hay, cnt)) \ _MOD
	loop
	repeat _n - _m + 1
		_i = cnt
		if _ph == _hh {
			_ok = 1
			repeat _m
				if peek(_pat, cnt) != peek(_hay, _i + cnt) : _ok = 0 : break
			loop
			if _ok : return _i
		}
		if _i < _n - _m {
			_hh = ((_hh - peek(_hay, _i) * _h) * _BASE + peek(_hay, _i + _m)) \ _MOD
			if _hh < 0 : _hh += _MOD
		}
	loop
	return -1
#global

; ----- 10. String reverse -----
#module
#deffunc str_reverse var _s, var _out, local _n, local _i
	_n = strlen(_s)
	sdim _out, _n + 1
	repeat _n
		_i = _n - 1 - cnt
		poke _out, cnt, peek(_s, _i)
	loop
	poke _out, _n, 0
	return
#global

; ===== デモ =====
	mes "=== 文字列検索 ==="
	hay = "ABAAABCDABAABCABAB"
	pat = "ABAB"
	mes "hay = " + hay
	mes "pat = " + pat
	mes strf("Naive(hay, pat) = %d",       naive_find(hay, pat))
	mes strf("KMP(hay, pat) = %d",         kmp_find(hay, pat))
	mes strf("BoyerMoore(hay, pat) = %d",  bm_find(hay, pat))
	mes strf("Rabin-Karp(hay, pat) = %d",  rabin_karp(hay, pat))

	mes ""
	s = "Hello, World!"
	str_reverse s, r
	mes strf("reverse('%s') = '%s'", s, r)
	end 0