在Go语言中进行字符串匹配算法常见的包括包括暴力匹配、KMP算法和Boyer-Moore算法。
暴力匹配算法
暴力匹配算法是一种简单直观的字符串匹配方法。它从主串中的每一个可能的位置开始,尝试与模式串进行匹配,如果匹配失败,则将主串的位置后移一位,直到找到匹配或主串被遍历完。
原理:
- 从主串的第一个字符开始,与模式串的第一个字符进行比较。
- 如果匹配成功,继续比较主串和模式串的下一个字符,直到匹配完成或出现不匹配的字符。
- 如果不匹配,将主串的位置后移一位,再次与模式串的第一个字符进行比较,重复此过程。
下面是Go中的暴力匹配算法示例:
func bruteForceMatch(mainStr, patternStr string) int {
mainLen := len(mainStr)
patternLen := len(patternStr)
for i := 0; i <= mainLen-patternLen; i++ {
j := 0
for j < patternLen && mainStr[i+j] == patternStr[j] {
j++
}
if j == patternLen {
return i // 匹配成功,返回主串中的位置
}
}
return -1 // 未找到匹配
}
KMP算法
KMP算法是一种高效的字符串匹配算法,它利用了模式串的前缀信息,避免了不必要的比较。
原理:
- 构建部分匹配表(也称为前缀表),用于记录模式串中每个位置的最长公共前后缀长度。
- 在匹配过程中,根据部分匹配表的信息,调整主串和模式串的比较位置,以减少不必要的比较。
- 当发生不匹配时,通过部分匹配表,将模式串向右移动尽可能远的位置,继续匹配。
下面是Go中的KMP算法示例:
func buildPartialMatchTable(patternStr string) []int {
patternLen := len(patternStr)
table := make([]int, patternLen)
table[0] = 0
j := 0
for i := 1; i < patternLen; i++ {
for j > 0 && patternStr[i] != patternStr[j] {
j = table[j-1]
}
if patternStr[i] == patternStr[j] {
j++
}
table[i] = j
}
return table
}
func KMPSearch(mainStr, patternStr string) int {
mainLen := len(mainStr)
patternLen := len(patternStr)
table := buildPartialMatchTable(patternStr)
j := 0
for i := 0; i < mainLen; i++ {
for j > 0 && mainStr[i] != patternStr[j] {
j = table[j-1]
}
if mainStr[i] == patternStr[j] {
j++
}
if j == patternLen {
return i - patternLen + 1 // 匹配成功,返回主串中的位置
}
}
return -1 // 未找到匹配
}
Boyer-Moore算法
Boyer-Moore算法是一种高效的字符串匹配算法,它通过从右向左的方式进行匹配,利用坏字符规则和好后缀规则来跳过不必要的比较。
原理:
- 预处理模式串,生成坏字符表和好后缀表。
- 在匹配过程中,从右向左比较模式串和主串,根据坏字符表和好后缀表,调整模式串的位置。
- 根据坏字符表找到不匹配字符在模式串中的最右位置,根据好后缀表找到好后缀的匹配段。
以下是Go中的Boyer-Moore算法示例:
func buildBadCharTable(patternStr string) map[byte]int {
table := make(map[byte]int)
patternLen := len(patternStr)
for i := 0; i < patternLen-1; i++ {
table[patternStr[i]] = patternLen - 1 - i
}
return table
}
func buildGoodSuffixTable(patternStr string) []int {
patternLen := len(patternStr)
table := make([]int, patternLen)
suffix := make([]int, patternLen)
for i := patternLen - 2; i >= 0; i-- {
j := i
for j >= 0 && patternStr[j] == patternStr[patternLen-1-i+j] {
j--
}
suffix[i] = i - j
}
for i := 0; i < patternLen-1; i++ {
table[i] = patternLen
}
for i := 0; i < patternLen-1; i++ {
table[patternLen-1-suffix[i]] = patternLen - 1 - i
}
return table
}
func BoyerMooreSearch(mainStr, patternStr string) int {
mainLen := len(mainStr)
patternLen := len(patternStr)
badCharTable := buildBadCharTable(patternStr)
goodSuffixTable := buildGoodSuffixTable(patternStr)
i := patternLen - 1
for i < mainLen {
j := patternLen - 1
for j >= 0 && mainStr[i] == patternStr[j] {
i--
j--
}
if j < 0 {
return i + 1 // 匹配成功,返回主串中的位置
}
moveByBadChar := j - badCharTable[mainStr[i]]
moveByGoodSuffix := 0
if j < patternLen-1 {
moveByGoodSuffix = moveByGoodSuffixRule(j, patternLen, goodSuffixTable)
}
i += max(moveByBadChar, moveByGoodSuffix)
}
return
-1 // 未找到匹配
}
func moveByGoodSuffixRule(badCharIdx, patternLen int, goodSuffixTable []int) int {
k := patternLen - 1 - badCharIdx
if goodSuffixTable[k] != -1 {
return badCharIdx - goodSuffixTable[k] + 1
} else {
for r := badCharIdx + 2; r <= patternLen-1; r++ {
if isPrefix(patternLen, patternLen-r, patternLen-1) {
return r
}
}
return patternLen
}
}
func isPrefix(p, i, j int) bool {
for i < p && j < p {
if patternStr[i] != patternStr[j] {
return false
}
i++
j++
}
return true
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
在上述代码中,BoyerMooreSearch函数实现了Boyer-Moore算法,通过坏字符表和好后缀表来进行匹配。buildBadCharTable和buildGoodSuffixTable函数用于构建坏字符表和好后缀表。moveByGoodSuffixRule函数用于根据好后缀规则计算移动距离。