package stdlib import ( "regexp" "strings" "github.com/d5/tengo/objects" ) var textModule = map[string]objects.Object{ // re_match(pattern, text) => bool/error "re_match": &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.ErrInvalidTypeConversion return } s2, ok := objects.ToString(args[1]) if !ok { err = objects.ErrInvalidTypeConversion return } matched, err := regexp.MatchString(s1, s2) if err != nil { ret = wrapError(err) return } if matched { ret = objects.TrueValue } else { ret = objects.FalseValue } return }, }, // re_find(pattern, text) => array(array({text:,begin:,end:}))/undefined // re_find(pattern, text, maxCount) => array(array({text:,begin:,end:}))/undefined "re_find": &objects.UserFunction{ Value: func(args ...objects.Object) (ret objects.Object, err error) { numArgs := len(args) if numArgs != 2 && numArgs != 3 { err = objects.ErrWrongNumArguments return } s1, ok := objects.ToString(args[0]) if !ok { err = objects.ErrInvalidTypeConversion return } re, err := regexp.Compile(s1) if err != nil { ret = wrapError(err) return } s2, ok := objects.ToString(args[1]) if !ok { err = objects.ErrInvalidTypeConversion return } if numArgs < 3 { m := re.FindStringSubmatchIndex(s2) 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: s2[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 } i3, ok := objects.ToInt(args[2]) if !ok { err = objects.ErrInvalidTypeConversion return } m := re.FindAllStringSubmatchIndex(s2, i3) 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: s2[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 }, }, // re_replace(pattern, text, repl) => string/error "re_replace": &objects.UserFunction{ Value: func(args ...objects.Object) (ret objects.Object, err error) { if len(args) != 3 { err = objects.ErrWrongNumArguments return } s1, ok := objects.ToString(args[0]) if !ok { err = objects.ErrInvalidTypeConversion return } s2, ok := objects.ToString(args[1]) if !ok { err = objects.ErrInvalidTypeConversion return } s3, ok := objects.ToString(args[2]) if !ok { err = objects.ErrInvalidTypeConversion return } re, err := regexp.Compile(s1) if err != nil { ret = wrapError(err) } else { ret = &objects.String{Value: re.ReplaceAllString(s2, s3)} } return }, }, // re_split(pattern, text) => array(string)/error // re_split(pattern, text, maxCount) => array(string)/error "re_split": &objects.UserFunction{ Value: func(args ...objects.Object) (ret objects.Object, err error) { numArgs := len(args) if numArgs != 2 && numArgs != 3 { err = objects.ErrWrongNumArguments return } s1, ok := objects.ToString(args[0]) if !ok { err = objects.ErrInvalidTypeConversion return } s2, ok := objects.ToString(args[1]) if !ok { err = objects.ErrInvalidTypeConversion return } var i3 = -1 if numArgs > 2 { i3, ok = objects.ToInt(args[2]) if !ok { err = objects.ErrInvalidTypeConversion return } } re, err := regexp.Compile(s1) if err != nil { ret = wrapError(err) return } arr := &objects.Array{} for _, s := range re.Split(s2, i3) { arr.Value = append(arr.Value, &objects.String{Value: s}) } ret = arr return }, }, // re_compile(pattern) => Regexp/error "re_compile": &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.ErrInvalidTypeConversion return } re, err := regexp.Compile(s1) if err != nil { ret = wrapError(err) } else { ret = stringsRegexpImmutableMap(re) } return }, }, // compare(a, b) => int "compare": FuncASSRI(strings.Compare), // contains(s, substr) => bool "contains": FuncASSRB(strings.Contains), // contains_any(s, chars) => bool "contains_any": FuncASSRB(strings.ContainsAny), // count(s, substr) => int "count": FuncASSRI(strings.Count), // "equal_fold(s, t) => bool "equal_fold": FuncASSRB(strings.EqualFold), // fields(s) => array(string) "fields": FuncASRSs(strings.Fields), // has_prefix(s, prefix) => bool "has_prefix": FuncASSRB(strings.HasPrefix), // has_suffix(s, suffix) => bool "has_suffix": FuncASSRB(strings.HasSuffix), // index(s, substr) => int "index": FuncASSRI(strings.Index), // index_any(s, chars) => int "index_any": FuncASSRI(strings.IndexAny), // join(arr, sep) => string "join": FuncASsSRS(strings.Join), // last_index(s, substr) => int "last_index": FuncASSRI(strings.LastIndex), // last_index_any(s, chars) => int "last_index_any": FuncASSRI(strings.LastIndexAny), // repeat(s, count) => string "repeat": FuncASIRS(strings.Repeat), // replace(s, old, new, n) => string "replace": &objects.UserFunction{ Value: func(args ...objects.Object) (ret objects.Object, err error) { if len(args) != 4 { err = objects.ErrWrongNumArguments return } s1, ok := objects.ToString(args[0]) if !ok { err = objects.ErrInvalidTypeConversion return } s2, ok := objects.ToString(args[1]) if !ok { err = objects.ErrInvalidTypeConversion return } s3, ok := objects.ToString(args[2]) if !ok { err = objects.ErrInvalidTypeConversion return } i4, ok := objects.ToInt(args[3]) if !ok { err = objects.ErrInvalidTypeConversion return } ret = &objects.String{Value: strings.Replace(s1, s2, s3, i4)} return }, }, // split(s, sep) => []string "split": FuncASSRSs(strings.Split), // split_after(s, sep) => []string "split_after": FuncASSRSs(strings.SplitAfter), // split_after_n(s, sep, n) => []string "split_after_n": FuncASSIRSs(strings.SplitAfterN), // split_n(s, sep, n) => []string "split_n": FuncASSIRSs(strings.SplitN), // title(s) => string "title": FuncASRS(strings.Title), // to_lower(s) => string "to_lower": FuncASRS(strings.ToLower), // to_title(s) => string "to_title": FuncASRS(strings.ToTitle), // to_upper(s) => string "to_upper": FuncASRS(strings.ToUpper), // trim_left(s, cutset) => string "trim_left": FuncASSRS(strings.TrimLeft), // trim_prefix(s, prefix) => string "trim_prefix": FuncASSRS(strings.TrimPrefix), // trim_right(s, cutset) => string "trim_right": FuncASSRS(strings.TrimRight), // trim_space(s) => string "trim_space": FuncASRS(strings.TrimSpace), // trim_suffix(s, suffix) => string "trim_suffix": FuncASSRS(strings.TrimSuffix), } func stringsRegexpImmutableMap(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.ErrInvalidTypeConversion 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.ErrInvalidTypeConversion 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.ErrInvalidTypeConversion 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.ErrInvalidTypeConversion return } s2, ok := objects.ToString(args[1]) if !ok { err = objects.ErrInvalidTypeConversion return } ret = &objects.String{Value: re.ReplaceAllString(s1, s2)} 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.ErrInvalidTypeConversion return } var i2 = -1 if numArgs > 1 { i2, ok = objects.ToInt(args[1]) if !ok { err = objects.ErrInvalidTypeConversion return } } arr := &objects.Array{} for _, s := range re.Split(s1, i2) { arr.Value = append(arr.Value, &objects.String{Value: s}) } ret = arr return }, }, }, } }