diff --git a/README.md b/README.md index ad285e5ae..1c5a63d6a 100644 --- a/README.md +++ b/README.md @@ -1097,6 +1097,7 @@ func PrettyJSON(v any) (string, error) func RenderTemplate(input string, data any, fns template.FuncMap, isFile ...bool) string func RenderText(input string, data any, fns template.FuncMap, isFile ...bool) string func WrapTag(s, tag string) string +func SubstrCount(s string, needle string, params ...uint64) (int, error) ``` ### System Utils diff --git a/strutil/strutil.go b/strutil/strutil.go index ea1f69d5d..7b617fc94 100644 --- a/strutil/strutil.go +++ b/strutil/strutil.go @@ -4,6 +4,7 @@ package strutil import ( "bytes" "encoding/json" + "errors" "fmt" "strings" "text/template" @@ -88,3 +89,35 @@ func WrapTag(s, tag string) string { } return fmt.Sprintf("<%s>%s", tag, s, tag) } + +// SubstrCount returns the number of times the substr substring occurs in the s string. +// Actually, it comes from strings.Count(). +// s The string to search in +// substr The substring to search for +// params[0] The offset where to start counting. +// params[1] The maximum length after the specified offset to search for the substring. +func SubstrCount(s string, substr string, params ...uint64) (int, error) { + larg := len(params) + hasArgs := larg != 0 + if hasArgs && larg > 2 { + return 0, errors.New("too many parameters") + } + if !hasArgs { + return strings.Count(s, substr), nil + } + strlen := len(s) + offset := 0 + end := strlen + if hasArgs { + offset = int(params[0]) + if larg == 2 { + length := int(params[1]) + end = offset + length + } + if end > strlen { + end = strlen + } + } + s = string([]rune(s)[offset:end]) + return strings.Count(s, substr), nil +} diff --git a/strutil/strutil_test.go b/strutil/strutil_test.go index 45f7d6661..ee204cf35 100644 --- a/strutil/strutil_test.go +++ b/strutil/strutil_test.go @@ -34,6 +34,23 @@ func TestWrapTag(t *testing.T) { assert.Eq(t, "abc", strutil.WrapTag("abc", "info")) } +func TestSubstrCount(t *testing.T) { + s := "I'm fine, thank you, and you" + substr := "you" + res, err := strutil.SubstrCount(s, substr) + assert.NoErr(t, err) + assert.Eq(t, 2, res) + res1, err := strutil.SubstrCount(s, substr, 18) + assert.NoErr(t, err) + assert.Eq(t, 1, res1) + res2, err := strutil.SubstrCount(s, substr, 17, 100) + assert.NoErr(t, err) + assert.Eq(t, 1, res2) + res3, err := strutil.SubstrCount(s, substr, 16) + assert.NoErr(t, err) + assert.Eq(t, 2, res3) +} + func TestPrettyJSON(t *testing.T) { tests := []any{ map[string]int{"a": 1},