Skip to content

Commit 167f0b2

Browse files
Support for regex MatchString function (#284)
* Fix for String In issue * added check for isvalid condition * removed extra nil check and len check * Antlr4.9 and go runtime changes * Update ANTLR.md * updated with review comments * remove rule entry changes * removing rule entry from knowledgebase library * added comments * updated with review comments * updated go.mod * Added UUID import * Minor comment changes * reverted back * minor code comment changes * Support for regex match string function
1 parent 7934a3b commit 167f0b2

File tree

8 files changed

+161
-7
lines changed

8 files changed

+161
-7
lines changed

docs/cn/Function_cn.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -817,6 +817,27 @@ rule TrimText "Do something when Fact.Text is 'ABC'" {
817817
}
818818
```
819819
820+
821+
### string.MatchString() string
822+
823+
`MatchString` MatchString reports whether the string s contains any match of the regular expression pattern. Similar to golang [MatchString](https://pkg.go.dev/regexp#MatchString)
824+
825+
#### Returns
826+
827+
* True if the `regexPattern` matches the string s
828+
* False if the `regexPattern` doesn't match the string s
829+
830+
#### Example
831+
832+
```Shell
833+
rule MatchStringText "Return true when regex pattern matches the string" {
834+
when
835+
Fact.Text.MatchString("B([a-z]+)ck")
836+
then
837+
Fact.DoSomething();
838+
}
839+
```
840+
820841
### array.Len() int
821842
822843
`Len` 返回数据或者切片的长度.

docs/de/Function_de.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -846,6 +846,27 @@ rule TrimText "Do something when Fact.Text is 'ABC'" {
846846
}
847847
```
848848
849+
850+
### string.MatchString() string
851+
852+
`MatchString` MatchString reports whether the string s contains any match of the regular expression pattern. Similar to golang [MatchString](https://pkg.go.dev/regexp#MatchString)
853+
854+
#### Returns
855+
856+
* True if the `regexPattern` matches the string s
857+
* False if the `regexPattern` doesn't match the string s
858+
859+
#### Example
860+
861+
```Shell
862+
rule MatchStringText "Return true when regex pattern matches the string" {
863+
when
864+
Fact.Text.MatchString("B([a-z]+)ck")
865+
then
866+
Fact.DoSomething();
867+
}
868+
```
869+
849870
### array.Len() int
850871
851872
`Len` will return the length of the array/slice.

docs/en/Function_en.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -833,6 +833,27 @@ rule TrimText "Do something when Fact.Text is 'ABC'" {
833833
}
834834
```
835835
836+
837+
### string.MatchString() string
838+
839+
`MatchString` MatchString reports whether the string s contains any match of the regular expression pattern. Similar to golang [MatchString](https://pkg.go.dev/regexp#MatchString)
840+
841+
#### Returns
842+
843+
* True if the `regexPattern` matches the string s
844+
* False if the `regexPattern` doesn't match the string s
845+
846+
#### Example
847+
848+
```Shell
849+
rule MatchStringText "Return true when regex pattern matches the string" {
850+
when
851+
Fact.Text.MatchString("B([a-z]+)ck")
852+
then
853+
Fact.DoSomething();
854+
}
855+
```
856+
836857
### array.Len() int
837858
838859
`Len` will return the length of the array/slice.

docs/id/Function_id.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,26 @@ rule TrimText "Do something when Fact.Text is 'ABC'" {
819819
}
820820
```
821821
822+
### string.MatchString() string
823+
824+
`MatchString` MatchString reports whether the string s contains any match of the regular expression pattern. Similar to golang [MatchString](https://pkg.go.dev/regexp#MatchString)
825+
826+
#### Returns
827+
828+
* True if the `regexPattern` matches the string s
829+
* False if the `regexPattern` doesn't match the string s
830+
831+
#### Example
832+
833+
```Shell
834+
rule MatchStringText "Return true when regex pattern matches the string" {
835+
when
836+
Fact.Text.MatchString("B([a-z]+)ck")
837+
then
838+
Fact.DoSomething();
839+
}
840+
```
841+
822842
### array.Len() int
823843
824844
`Len` will return the length of the array/slice.

examples/StringInExample_test.go renamed to examples/StringFunctions_test.go

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,28 @@ import (
2424
)
2525

2626
const (
27-
Rule1 = `
28-
rule ColorCheck "test 1" {
27+
strInConditionRule = `
28+
rule StrInConditionCheck "test 1" {
2929
when
3030
Color.Name.In("Black", "Yellow")
3131
then
3232
Color.Message = "Its either black or yellow!!!";
33-
Retract("ColorCheck");
33+
Retract("StrInConditionCheck");
34+
}
35+
`
36+
strMatchStringConditionRule = `
37+
rule strMatchStringConditionCheck "test 2" {
38+
when
39+
Color.Name.MatchString("B([a-z]+)ck")
40+
then
41+
Color.Message = "yes its Black!!!";
42+
Retract("strMatchStringConditionCheck");
3443
}
3544
`
3645
)
3746

3847
type Color struct {
39-
Name string
48+
Name string
4049
Message string
4150
}
4251

@@ -45,19 +54,40 @@ func TestStringInExample(t *testing.T) {
4554
Name: "Black",
4655
Message: "",
4756
}
48-
4957
dataContext := ast.NewDataContext()
5058
err := dataContext.Add("Color", color)
5159
assert.NoError(t, err)
5260

5361
// Prepare knowledgebase library and load it with our rule.
5462
lib := ast.NewKnowledgeLibrary()
5563
rb := builder.NewRuleBuilder(lib)
56-
err = rb.BuildRuleFromResource("Test", "0.1.1", pkg.NewBytesResource([]byte(Rule1)))
64+
err = rb.BuildRuleFromResource("Test", "0.1.1", pkg.NewBytesResource([]byte(strInConditionRule)))
5765
assert.NoError(t, err)
5866
kb := lib.NewKnowledgeBaseInstance("Test", "0.1.1")
5967
eng1 := &engine.GruleEngine{MaxCycle: 1}
6068
err = eng1.Execute(dataContext, kb)
6169
assert.NoError(t, err)
6270
assert.Equal(t, "Its either black or yellow!!!", color.Message)
6371
}
72+
73+
func TestStringMatchStringExample(t *testing.T) {
74+
color := &Color{
75+
Name: "Black",
76+
Message: "",
77+
}
78+
79+
dataContext := ast.NewDataContext()
80+
err := dataContext.Add("Color", color)
81+
assert.NoError(t, err)
82+
83+
// Prepare knowledgebase library and load it with our rule.
84+
lib := ast.NewKnowledgeLibrary()
85+
rb := builder.NewRuleBuilder(lib)
86+
err = rb.BuildRuleFromResource("Test", "0.1.1", pkg.NewBytesResource([]byte(strMatchStringConditionRule)))
87+
assert.NoError(t, err)
88+
kb := lib.NewKnowledgeBaseInstance("Test", "0.1.1")
89+
eng1 := &engine.GruleEngine{MaxCycle: 1}
90+
err = eng1.Execute(dataContext, kb)
91+
assert.NoError(t, err)
92+
assert.Equal(t, "yes its Black!!!", color.Message)
93+
}

model/DataAccessLayer.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ package model
1717
import (
1818
"fmt"
1919
"reflect"
20+
"regexp"
2021
"strings"
21-
2222
"github.com/hyperjumptech/grule-rule-engine/pkg"
2323
)
2424

@@ -220,6 +220,18 @@ func StrIn(str string, arg []reflect.Value) (reflect.Value, error) {
220220
return reflect.ValueOf(false), nil
221221
}
222222

223+
// StrMatchRegexPattern reports whether the string s contains any match of the regular expression pattern.
224+
func StrMatchRegexPattern(str string, arg []reflect.Value) (reflect.Value, error) {
225+
if arg == nil || len(arg) != 1 || arg[0].Kind() != reflect.String {
226+
return reflect.ValueOf(nil), fmt.Errorf("function StrMatchRegexPattern requires 1 string argument")
227+
}
228+
m, err := regexp.MatchString(arg[0].String(), str)
229+
if err != nil {
230+
return reflect.ValueOf(nil), fmt.Errorf("function StrMatchRegexPattern requires valid regex pattern")
231+
}
232+
return reflect.ValueOf(m), nil
233+
}
234+
223235
// ArrMapLen will return the size of underlying map, array or slice
224236
func ArrMapLen(arr reflect.Value, arg []reflect.Value) (reflect.Value, error) {
225237
if arg != nil && len(arg) != 0 {

model/DataAccessLayer_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,4 +181,31 @@ func TestStrIn_Accepts_Empty_Arguments(t *testing.T) {
181181
b := "Black"
182182
_, err := StrIn(b, []reflect.Value{})
183183
assert.NoError(t, err)
184+
}
185+
186+
187+
func TestStrMatchRegexPattern_Valid_Regex_Pattern(t *testing.T) {
188+
regex := "p([a-z]+)ch"
189+
str := "peach"
190+
191+
val, err := StrMatchRegexPattern(str, []reflect.Value{reflect.ValueOf(regex)})
192+
assert.NoError(t, err)
193+
assert.True(t, val.Bool())
194+
}
195+
196+
func TestStrMatchRegexPattern_InValid_Regex_Pattern(t *testing.T) {
197+
regex := "p([a-z]ch"
198+
str := "peach"
199+
200+
_, err := StrMatchRegexPattern(str, []reflect.Value{reflect.ValueOf(regex)})
201+
assert.Error(t, err)
202+
}
203+
204+
func TestStrMatchRegexPattern_Not_Match(t *testing.T) {
205+
regex := "p([a-z]+)ch"
206+
str := "pe1ch"
207+
208+
val, err := StrMatchRegexPattern(str, []reflect.Value{reflect.ValueOf(regex)})
209+
assert.NoError(t, err)
210+
assert.False(t, val.Bool())
184211
}

model/GoDataAccessLayer.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,8 @@ func (node *GoValueNode) CallFunction(funcName string, args ...reflect.Value) (r
349349
strfunc = StrTrim
350350
case "Len":
351351
strfunc = StrLen
352+
case "MatchString":
353+
strfunc = StrMatchRegexPattern
352354
}
353355
if strfunc != nil {
354356
val, err := strfunc(node.thisValue.String(), args)

0 commit comments

Comments
 (0)