Golang-string包
前言
从零开始学习golang,发现很多包的函数都不太熟悉,之前写了一个com包的,准备啃一下常用内置包的源码,然后把用法都记录一下,加深一下记忆,顺便学习一下大佬们们造的轮子。只记录非私有的函数,golang版本1.14.6,会写点注释。函数
1.Index(s, substr string) int
// Index returns the index of the first instance of substr in s, or -1 if substr is not present in s.
func Index(s, substr string) int {
n := len(substr)
switch {
case n == 0:
return 0
case n == 1:
return IndexByte(s, substr[0])
case n == len(s):
if substr == s {
return 0
}
return -1
case n > len(s):
return -1
//substr长度小于临界值
case n <= bytealg.MaxLen:
// Use brute force when s and substr both are small
//如果s和substr都比较小,使用暴力破解算法
//即从两个字符串的第一位开始比较,相同则比较下一位,不相同则用s的第二位比较substr的第一位依次类推直到查出结果或者循环结束返回-1
if len(s) <= bytealg.MaxBruteForce {
return bytealg.IndexString(s, substr)
}
//s长度较长,substr长度较小的使用其他的算法
c0 := substr[0]
c1 := substr[1]
//i是s上的定位,表示在这之前,都不存在s[i] == substr[0]
i := 0
//t是临界值,如果循环判断到s[t-1]都还不等于substr[0],则s不包含substr,返回-1
t := len(s) - n + 1
fails := 0
for i < t {
if s[i] != c0 {
// IndexByte is faster than bytealg.IndexString, so use it as long as
// we're not getting lots of false positives.
o := IndexByte(s[i:t], c0)
//剩余未判断的s不包含substr[0],则s不包含substr,返回-1
if o < 0 {
return -1
}
//剩余未判断的s包含substr[0]。i指向该位置
i += o
}
//上一个if条件不满足或者i已经指向下一个s[i] == substr[0]的位置
//所以s[i] == substr[0],s[i+1] == substr[1]并且后续也相等的话,返回结果i
if s[i+1] == c1 && s[i:i+n] == substr {
return i
}
fails++
i++
// Switch to bytealg.IndexString when IndexByte produces too many false positives.
//从第一位开始判断,当判断不成功的次数超过临界值的时候,转为使用bytealg.IndexString(暴力破解算法)
if fails > bytealg.Cutover(i) {
r := bytealg.IndexString(s[i:], substr)
if r >= 0 {
return r + i
}
return -1
}
}
return -1
}
//substr长度大于临界值使用RabinKarp算法
c0 := substr[0]
c1 := substr[1]
i := 0
t := len(s) - n + 1
fails := 0
for i < t {
if s[i] != c0 {
o := IndexByte(s[i:t], c0)
if o < 0 {
return -1
}
i += o
}
if s[i+1] == c1 && s[i:i+n] == substr {
return i
}
i++
fails++
//和上面只是fails临界值的判断条件和调用的函数不一样
if fails >= 4+i>>4 && i < t {
// See comment in ../bytes/bytes.go.
j := indexRabinKarp(s[i:], substr)
if j < 0 {
return -1
}
return i + j
}
}
return -1
}
//借用一下别人造的轮子: https://blog.csdn.net/seacowtech/article/details/79256299
//Rabin-Karp算法的思想:
//1.假设子串的长度为M,目标字符串的长度为N
//2.计算子串的hash值
//3.计算目标字符串中每个长度为M的子串的hash值(共需要计算N-M+1次)
//4.比较hash值
//5.如果hash值不同,字符串必然不匹配,如果hash值相同,还需要使用朴素算法再次判断
func indexRabinKarp(s, substr string) int {
// Rabin-Karp search
hashss, pow := hashStr(substr)
n := len(substr)
var h uint32
for i := 0; i < n; i++ {
h = h*primeRK + uint32(s[i])
}
if h == hashss && s[:n] == substr {
return 0
}
for i := n; i < len(s); {
h *= primeRK
h += uint32(s[i])
h -= pow * uint32(s[i-n])
i++
if h == hashss && s[i-n:i] == substr {
return i - n
}
}
return -1
}
未完待续…