I want to find the index of all occurrences of a string contained within a byte array.
func findAllOccurrences(data []byte, searches []string) map[string][]int {
var results map[string][]int
for _, search := range searches {
firstMatch = bytes.Index(data, []byte(search))
results[search] = append(results[search], firstMatch)
// How do I find subsequent the rest of the matches?
}
return results
}
Finding the first Index()
is simple enough, but how can I find all of them in an idiomatic way without consuming unnecessary memory?
Okay, so here is the solution from my comment by reading the LastIndex
instead of first, not sure if it is efficient, but this does work, you just get indexes in an inverted order, which you can always fix at the time of reading.
package main
import (
"fmt"
"bytes"
)
func main() {
str1:= "foobarfoobarfoobarfoobarfoofoobar"
arr := make([]string, 2)
arr[0]="foo"
arr[1]="bar"
res:=findAllOccurrences([]byte(str1), arr)
fmt.Println(res)
}
func findAllOccurrences(data []byte, searches []string) map[string][]int {
results:= make(map[string][]int,0)
for _, search := range searches {
index := len(data)
tmp:=data
for true{
match := bytes.LastIndex(tmp[0:index], []byte(search))
if match==-1{
break
}else{
index=match
results[search]=append(results[search], match)
}
}
}
return results
}
Hope this helps! :)
As ishaan's answer shows, you can assign data
to another slice variable for each search, and then reslice that variable after each match. The assignment only copies length, capacity, and a pointer. Reslicing only changes the length and pointer on the slice variable: it won't affect the underlying array, and it is not a new allocation. I added this answer to clarify the memory efficiency, and to demonstrate that you can still use bytes.Index
and you can use it as your starting point and incrementer in a traditional for loop:
package main
import (
"bytes"
"fmt"
)
func findAllOccurrences(data []byte, searches []string) map[string][]int {
results := make(map[string][]int)
for _, search := range searches {
searchData := data
term := []byte(search)
for x, d := bytes.Index(searchData, term), 0; x > -1; x, d = bytes.Index(searchData, term), d+x+1 {
results[search] = append(results[search], x+d)
searchData = searchData[x+1 : len(searchData)]
}
}
return results
}
func main() {
fmt.Println(findAllOccurrences([]byte(`foo foo hey foo`), []string{`foo`, `hey`, ` `}))
}
prints
map[foo:[0 4 12] hey:[8] :[3 7 11]]