Golang Rabin-karp Algorithm
在某個機會下稍稍研究了一下這個 Multiple Pattern 字串匹配演算法,而下面則是一些演算法的核心理解與實作紀錄。 由於相關的 code 在網路上其實都可以搜尋到資料,所以這邊僅撰寫
理解演算法核心後自行練習的 Single Pattern 。
核心與步驟
- 計算出 sensitive word 的 hash value
-
Hash value 的 f(x):
以字符總數為進位單位,假設稱為 M,並計算 sensitive word
中各字碼 * M ^ (len -1) 的總和。
- Ascii = 128
- Golang Unicode = 16777619
e.g. str = “abc”,M = 128,Len(str) = 3
Hash value = 97 * M^2 + 98 * M +97
= 1601891
-
取出句子(text)中前面 Len 長度的字節,進行 hash 並與
sensitive word 的 hash 進行比較。
通常會以最短 sensitive word 的長度為依據。
-
匹配
- 代表此句中含有 sensitive word
-
不匹配
1. 減掉字首的 hash 值
2. hash * M + 下一個字節碼,再與之比對,值至比對完
成。
e.g. text = “cedabcfeap”,len = 3
所以將 “ced”進行 hash,最後會得出不匹配,
這時應將比對 “eda”,所以減去 c的 hash 值後乘上 M,
再加上 a 的字節碼,成為新的 hash 值。再將此 hash 值,
與 sensitive word 的 hash 值進行比對。
實作
package main
import "fmt"
const M = 128
func Hash(str string) rune {
h := rune(0)
for i := 0; i < len(str); i++ {
h = (h*M + rune(str[i]))
}
return h
}
func Match(txt string, sensitive string) int {
txt_len := len(txt)
pattern_len := len(sensitive)
hash := Hash(txt[:pattern_len])
sensitive_hash := Hash(sensitive)
var pow rune = 1 // pow = M^(pattern_len-1)
for i := 0; i < pattern_len-1; i++ {
pow = (pow * M)
}
count:=0
finall_index:=txt_len-pattern_len + 1
for i := 0; i < finall_index ; i++ {
if i > 0{
hash = hash - pow*rune(txt[i-1])
hash = hash * M + rune(txt[i+pattern_len-1])
}
if hash == sensitive_hash && pattern_len > 0 {
count++
}
}
return count
}
func main() {
txt := "hello abc world,abc"
sensitive := "abc"
result := Match(txt, sensitive)
fmt.Println(result)
}
0 意見