github.com/scottcagno/storage@v1.8.0/pkg/search/knuth-morris-pratt.go (about) 1 package search 2 3 // KnuthMorrisPratt algorithm is oftentimes only the best performing when it's used on shorter texts or 4 // if you are pre-computing the search tables beforehand. Otherwise, Boyer-Moore (and even Rabin-Karp) will 5 // beat it almost out most of the time. 6 type KnuthMorrisPratt struct{} 7 8 func NewKnuthMorrisPratt() *KnuthMorrisPratt { 9 return new(KnuthMorrisPratt) 10 } 11 12 func (kmp *KnuthMorrisPratt) String() string { 13 return "KNUTH-MORRIS-PRATT" 14 } 15 16 func (kmp *KnuthMorrisPratt) FindIndex(text, pattern []byte) int { 17 if text == nil || pattern == nil { 18 return -1 19 } 20 return knuthMorrisPrattFinder(text, pattern) 21 } 22 23 func (kmp *KnuthMorrisPratt) FindIndexString(text, pattern string) int { 24 return knuthMorrisPrattFinderString(text, pattern) 25 } 26 27 func knuthMorrisPrattFinder(text, pattern []byte) int { 28 nn := kmpFinder(text, pattern) 29 if len(nn) > 0 { 30 return nn[0] 31 } 32 return -1 33 } 34 35 func knuthMorrisPrattFinderString(text, pattern string) int { 36 nn := kmpFinderString(text, pattern) 37 if len(nn) > 0 { 38 return nn[0] 39 } 40 return -1 41 } 42 43 var patternSize = 86 44 45 func kmpFinder(s, sub []byte) []int { 46 next := preKMP(sub) 47 i, j := 0, 0 48 49 m, n := len(sub), len(s) 50 51 x, y := sub, s 52 var ret []int 53 54 //got zero target or want, just return empty result 55 if m == 0 || n == 0 { 56 return ret 57 } 58 59 //want string bigger than target string 60 if n < m { 61 return ret 62 } 63 64 for j < n { 65 for i > -1 && x[i] != y[j] { 66 i = next[i] 67 } 68 i++ 69 j++ 70 71 //fmt.Println(i, j) 72 if i >= m { 73 ret = append(ret, j-i) 74 //fmt.Println("find:", j, i) 75 i = next[i] 76 } 77 } 78 79 return ret 80 } 81 82 func preMP(x []byte) []int { 83 var i, j int 84 length := len(x) - 1 85 //var mpNext [patternSize]int 86 mpNext := make([]int, len(x)+1) 87 i = 0 88 j = -1 89 mpNext[0] = -1 90 91 for i < length { 92 for j > -1 && x[i] != x[j] { 93 j = mpNext[j] 94 } 95 i++ 96 j++ 97 mpNext[i] = j 98 } 99 return mpNext 100 } 101 102 func preKMP(x []byte) []int { 103 var i, j int 104 length := len(x) - 1 105 //var kmpNext [patternSize]int 106 kmpNext := make([]int, len(x)+1) 107 i = 0 108 j = -1 109 kmpNext[0] = -1 110 111 for i < length { 112 for j > -1 && x[i] != x[j] { 113 j = kmpNext[j] 114 } 115 116 i++ 117 j++ 118 119 if x[i] == x[j] { 120 kmpNext[i] = kmpNext[j] 121 } else { 122 kmpNext[i] = j 123 } 124 } 125 return kmpNext 126 } 127 128 func kmpFinderString(s, sub string) []int { 129 next := preKMPString(sub) 130 i, j := 0, 0 131 132 m, n := len(sub), len(s) 133 134 x, y := []byte(sub), []byte(s) 135 var ret []int 136 137 //got zero target or want, just return empty result 138 if m == 0 || n == 0 { 139 return ret 140 } 141 142 //want string bigger than target string 143 if n < m { 144 return ret 145 } 146 147 for j < n { 148 for i > -1 && x[i] != y[j] { 149 i = next[i] 150 } 151 i++ 152 j++ 153 154 //fmt.Println(i, j) 155 if i >= m { 156 ret = append(ret, j-i) 157 //fmt.Println("find:", j, i) 158 i = next[i] 159 } 160 } 161 162 return ret 163 } 164 165 func preMPString(x string) []int { 166 var i, j int 167 length := len(x) - 1 168 //var mpNext [patternSize]int 169 mpNext := make([]int, len(x)+1) 170 i = 0 171 j = -1 172 mpNext[0] = -1 173 174 for i < length { 175 for j > -1 && x[i] != x[j] { 176 j = mpNext[j] 177 } 178 i++ 179 j++ 180 mpNext[i] = j 181 } 182 return mpNext 183 } 184 185 func preKMPString(x string) []int { 186 var i, j int 187 length := len(x) - 1 188 //var kmpNext [patternSize]int 189 kmpNext := make([]int, len(x)+1) 190 i = 0 191 j = -1 192 kmpNext[0] = -1 193 194 for i < length { 195 for j > -1 && x[i] != x[j] { 196 j = kmpNext[j] 197 } 198 199 i++ 200 j++ 201 202 if x[i] == x[j] { 203 kmpNext[i] = kmpNext[j] 204 } else { 205 kmpNext[i] = j 206 } 207 } 208 return kmpNext 209 }