Skip to content

Commit

Permalink
feat: add regex.replace(s, p, v) to builtin (#5179)
Browse files Browse the repository at this point in the history
* feat: add regex.replace(s, p, v) to builtin

Signed-off-by: boranx <boran.seref@gmail.com>
  • Loading branch information
boranx committed Sep 27, 2022
1 parent 00e835a commit 1d2173b
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 0 deletions.
14 changes: 14 additions & 0 deletions ast/builtins.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ var DefaultBuiltins = [...]*Builtin{
RegexTemplateMatch,
RegexFind,
RegexFindAllStringSubmatch,
RegexReplace,

// Sets
SetDiff,
Expand Down Expand Up @@ -1185,6 +1186,19 @@ The old string comparisons are done in argument order.`,
),
}

var RegexReplace = &Builtin{
Name: "regex.replace",
Description: `Find and replaces the text using the regular expression pattern.`,
Decl: types.NewFunction(
types.Args(
types.Named("s", types.S).Description("string being processed"),
types.Named("pattern", types.S).Description("regex pattern to be applied"),
types.Named("value", types.S).Description("regex value"),
),
types.Named("output", types.S),
),
}

var Trim = &Builtin{
Name: "trim",
Description: "Returns `value` with all leading or trailing instances of the `cutset` characters removed.",
Expand Down
30 changes: 30 additions & 0 deletions builtin_metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@
"regex.globs_match",
"regex.is_valid",
"regex.match",
"regex.replace",
"regex.split",
"regex.template_match"
],
Expand Down Expand Up @@ -10095,6 +10096,35 @@
},
"wasm": true
},
"regex.replace": {
"args": [
{
"description": "string being processed",
"name": "s",
"type": "string"
},
{
"description": "regex pattern to be applied",
"name": "pattern",
"type": "string"
},
{
"description": "regex value",
"name": "value",
"type": "string"
}
],
"available": [
"edge"
],
"description": "Find and replaces the text using the regular expression pattern.",
"introduced": "edge",
"result": {
"name": "output",
"type": "string"
},
"wasm": false
},
"regex.split": {
"args": [
{
Expand Down
20 changes: 20 additions & 0 deletions capabilities.json
Original file line number Diff line number Diff line change
Expand Up @@ -3137,6 +3137,26 @@
"type": "function"
}
},
{
"name": "regex.replace",
"decl": {
"args": [
{
"type": "string"
},
{
"type": "string"
},
{
"type": "string"
}
],
"result": {
"type": "string"
},
"type": "function"
}
},
{
"name": "regex.split",
"decl": {
Expand Down
39 changes: 39 additions & 0 deletions test/cases/testdata/regexreplace/test-regexreplace-0001.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
cases:
- data: {}
modules:
- |
package test
p = x {
s := "-wy-wxxy-"
x := regex.replace(s, "w(x*)y", "0")
}
note: 'regex.replace: test pattern match and replace'
query: data.test.p = x
want_result:
- x: -0-0-
- data: {}
modules:
- |
package test
p = x {
s := "foo"
x := regex.replace(s, "(foo)", "$1$1")
}
note: 'regex.replace: work with groups'
query: data.test.p = x
want_result:
- x: foofoo
- data: {}
modules:
- |
package test
p = x {
s := "foo"
x := regex.replace(s, "[", "$1")
}
note: 'regex.replace: bad regex pattern: Syntax error'
query: data.test.p = x
want_result: []
27 changes: 27 additions & 0 deletions topdown/regex.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,32 @@ func builtinRegexFindAllStringSubmatch(a, b, c ast.Value) (ast.Value, error) {
return ast.NewArray(outer...), nil
}

func builtinRegexReplace(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error {
base, err := builtins.StringOperand(operands[0].Value, 1)
if err != nil {
return err
}

pattern, err := builtins.StringOperand(operands[1].Value, 2)
if err != nil {
return err
}

value, err := builtins.StringOperand(operands[2].Value, 3)
if err != nil {
return err
}

re, err := getRegexp(string(pattern))
if err != nil {
return err
}

res := re.ReplaceAllString(string(base), string(value))

return iter(ast.StringTerm(res))
}

func init() {
regexpCache = map[string]*regexp.Regexp{}
RegisterBuiltinFunc(ast.RegexIsValid.Name, builtinRegexIsValid)
Expand All @@ -215,4 +241,5 @@ func init() {
RegisterFunctionalBuiltin4(ast.RegexTemplateMatch.Name, builtinRegexMatchTemplate)
RegisterFunctionalBuiltin3(ast.RegexFind.Name, builtinRegexFind)
RegisterFunctionalBuiltin3(ast.RegexFindAllStringSubmatch.Name, builtinRegexFindAllStringSubmatch)
RegisterBuiltinFunc(ast.RegexReplace.Name, builtinRegexReplace)
}

0 comments on commit 1d2173b

Please sign in to comment.