mirror of
https://github.com/open-policy-agent/opa.git
synced 2026-08-12 19:32:48 -06:00
Implement a built-in function for String count
Fixes #6827 Signed-off-by: Manish Giri <manish.giri.me@gmail.com>
This commit is contained in:
@@ -120,6 +120,7 @@ var DefaultBuiltins = [...]*Builtin{
|
||||
Lower,
|
||||
Upper,
|
||||
Contains,
|
||||
StringCount,
|
||||
StartsWith,
|
||||
EndsWith,
|
||||
Split,
|
||||
@@ -1109,6 +1110,19 @@ var Contains = &Builtin{
|
||||
Categories: stringsCat,
|
||||
}
|
||||
|
||||
var StringCount = &Builtin{
|
||||
Name: "strings.count",
|
||||
Description: "Returns the number of non-overlapping instances of a substring in a string.",
|
||||
Decl: types.NewFunction(
|
||||
types.Args(
|
||||
types.Named("search", types.S).Description("string to search in"),
|
||||
types.Named("substring", types.S).Description("substring to look for"),
|
||||
),
|
||||
types.Named("output", types.N).Description("count of occurrences, `0` if not found"),
|
||||
),
|
||||
Categories: stringsCat,
|
||||
}
|
||||
|
||||
var StartsWith = &Builtin{
|
||||
Name: "startswith",
|
||||
Description: "Returns true if the search string begins with the base string.",
|
||||
|
||||
@@ -178,6 +178,7 @@
|
||||
"startswith",
|
||||
"strings.any_prefix_match",
|
||||
"strings.any_suffix_match",
|
||||
"strings.count",
|
||||
"strings.render_template",
|
||||
"strings.replace_n",
|
||||
"strings.reverse",
|
||||
@@ -17382,6 +17383,31 @@
|
||||
},
|
||||
"wasm": false
|
||||
},
|
||||
"strings.count": {
|
||||
"args": [
|
||||
{
|
||||
"description": "string to search in",
|
||||
"name": "search",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"description": "substring to look for",
|
||||
"name": "substring",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"available": [
|
||||
"edge"
|
||||
],
|
||||
"description": "Returns the number of non-overlapping instances of a substring in a string.",
|
||||
"introduced": "edge",
|
||||
"result": {
|
||||
"description": "count of occurrences, `0` if not found",
|
||||
"name": "output",
|
||||
"type": "number"
|
||||
},
|
||||
"wasm": false
|
||||
},
|
||||
"strings.render_template": {
|
||||
"args": [
|
||||
{
|
||||
|
||||
@@ -3969,6 +3969,23 @@
|
||||
"type": "function"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "strings.count",
|
||||
"decl": {
|
||||
"args": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"result": {
|
||||
"type": "number"
|
||||
},
|
||||
"type": "function"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "strings.render_template",
|
||||
"decl": {
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
---
|
||||
cases:
|
||||
- note: "strings/count_single_word_match"
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
package test
|
||||
p := strings.count("cheese", "e")
|
||||
want_result:
|
||||
- x: 3
|
||||
- note: "strings/count_multiple_separate_matches"
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
package test
|
||||
p := strings.count("hello hello hello world", "hello")
|
||||
want_result:
|
||||
- x: 3
|
||||
- note: "strings/count_n_no_match"
|
||||
query: data.test.p = x
|
||||
modules:
|
||||
- |
|
||||
package test
|
||||
p := strings.count("dummy", "x")
|
||||
want_result:
|
||||
- x: 0
|
||||
@@ -310,6 +310,25 @@ func builtinContains(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term
|
||||
return iter(ast.BooleanTerm(strings.Contains(string(s), string(substr))))
|
||||
}
|
||||
|
||||
func builtinStringCount(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
|
||||
s, err := builtins.StringOperand(operands[0].Value, 1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
substr, err := builtins.StringOperand(operands[1].Value, 2)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
baseTerm := string(s)
|
||||
searchTerm := string(substr)
|
||||
|
||||
count := strings.Count(baseTerm, searchTerm)
|
||||
|
||||
return iter(ast.IntNumberTerm(count))
|
||||
}
|
||||
|
||||
func builtinStartsWith(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
|
||||
s, err := builtins.StringOperand(operands[0].Value, 1)
|
||||
if err != nil {
|
||||
@@ -570,6 +589,7 @@ func init() {
|
||||
RegisterBuiltinFunc(ast.IndexOfN.Name, builtinIndexOfN)
|
||||
RegisterBuiltinFunc(ast.Substring.Name, builtinSubstring)
|
||||
RegisterBuiltinFunc(ast.Contains.Name, builtinContains)
|
||||
RegisterBuiltinFunc(ast.StringCount.Name, builtinStringCount)
|
||||
RegisterBuiltinFunc(ast.StartsWith.Name, builtinStartsWith)
|
||||
RegisterBuiltinFunc(ast.EndsWith.Name, builtinEndsWith)
|
||||
RegisterBuiltinFunc(ast.Upper.Name, builtinUpper)
|
||||
|
||||
Reference in New Issue
Block a user