package stdlib import ( "regexp" "github.com/d5/tengo" "github.com/d5/tengo/objects" ) func makeTextRegexp(re *regexp.Regexp) *objects.ImmutableMap { return &objects.ImmutableMap{ Value: map[string]objects.Object{ // match(text) => bool "match": &objects.UserFunction{ Value: func(args ...objects.Object) (ret objects.Object, err error) { if len(args) != 1 { err = objects.ErrWrongNumArguments return } s1, ok := objects.ToString(args[0]) if !ok { err = objects.ErrInvalidArgumentType{ Name: "first", Expected: "string(compatible)", Found: args[0].TypeName(), } return } if re.MatchString(s1) { ret = objects.TrueValue } else { ret = objects.FalseValue } return }, }, // find(text) => array(array({text:,begin:,end:}))/undefined // find(text, maxCount) => array(array({text:,begin:,end:}))/undefined "find": &objects.UserFunction{ Value: func(args ...objects.Object) (ret objects.Object, err error) { numArgs := len(args) if numArgs != 1 && numArgs != 2 { err = objects.ErrWrongNumArguments return } s1, ok := objects.ToString(args[0]) if !ok { err = objects.ErrInvalidArgumentType{ Name: "first", Expected: "string(compatible)", Found: args[0].TypeName(), } return } if numArgs == 1 { m := re.FindStringSubmatchIndex(s1) if m == nil { ret = objects.UndefinedValue return } arr := &objects.Array{} for i := 0; i < len(m); i += 2 { arr.Value = append(arr.Value, &objects.ImmutableMap{Value: map[string]objects.Object{ "text": &objects.String{Value: s1[m[i]:m[i+1]]}, "begin": &objects.Int{Value: int64(m[i])}, "end": &objects.Int{Value: int64(m[i+1])}, }}) } ret = &objects.Array{Value: []objects.Object{arr}} return } i2, ok := objects.ToInt(args[1]) if !ok { err = objects.ErrInvalidArgumentType{ Name: "second", Expected: "int(compatible)", Found: args[1].TypeName(), } return } m := re.FindAllStringSubmatchIndex(s1, i2) if m == nil { ret = objects.UndefinedValue return } arr := &objects.Array{} for _, m := range m { subMatch := &objects.Array{} for i := 0; i < len(m); i += 2 { subMatch.Value = append(subMatch.Value, &objects.ImmutableMap{Value: map[string]objects.Object{ "text": &objects.String{Value: s1[m[i]:m[i+1]]}, "begin": &objects.Int{Value: int64(m[i])}, "end": &objects.Int{Value: int64(m[i+1])}, }}) } arr.Value = append(arr.Value, subMatch) } ret = arr return }, }, // replace(src, repl) => string "replace": &objects.UserFunction{ Value: func(args ...objects.Object) (ret objects.Object, err error) { if len(args) != 2 { err = objects.ErrWrongNumArguments return } s1, ok := objects.ToString(args[0]) if !ok { err = objects.ErrInvalidArgumentType{ Name: "first", Expected: "string(compatible)", Found: args[0].TypeName(), } return } s2, ok := objects.ToString(args[1]) if !ok { err = objects.ErrInvalidArgumentType{ Name: "second", Expected: "string(compatible)", Found: args[1].TypeName(), } return } s, ok := doTextRegexpReplace(re, s1, s2) if !ok { return nil, objects.ErrStringLimit } ret = &objects.String{Value: s} return }, }, // split(text) => array(string) // split(text, maxCount) => array(string) "split": &objects.UserFunction{ Value: func(args ...objects.Object) (ret objects.Object, err error) { numArgs := len(args) if numArgs != 1 && numArgs != 2 { err = objects.ErrWrongNumArguments return } s1, ok := objects.ToString(args[0]) if !ok { err = objects.ErrInvalidArgumentType{ Name: "first", Expected: "string(compatible)", Found: args[0].TypeName(), } return } var i2 = -1 if numArgs > 1 { i2, ok = objects.ToInt(args[1]) if !ok { err = objects.ErrInvalidArgumentType{ Name: "second", Expected: "int(compatible)", Found: args[1].TypeName(), } return } } arr := &objects.Array{} for _, s := range re.Split(s1, i2) { arr.Value = append(arr.Value, &objects.String{Value: s}) } ret = arr return }, }, }, } } // Size-limit checking implementation of regexp.ReplaceAllString. func doTextRegexpReplace(re *regexp.Regexp, src, repl string) (string, bool) { idx := 0 out := "" for _, m := range re.FindAllStringSubmatchIndex(src, -1) { var exp []byte exp = re.ExpandString(exp, repl, src, m) if len(out)+m[0]-idx+len(exp) > tengo.MaxStringLen { return "", false } out += src[idx:m[0]] + string(exp) idx = m[1] } if idx < len(src) { if len(out)+len(src)-idx > tengo.MaxStringLen { return "", false } out += src[idx:] } return string(out), true }