diff --git a/func-string.go b/func-string.go index 695cbd8..d86d5de 100644 --- a/func-string.go +++ b/func-string.go @@ -5,6 +5,7 @@ package expr import ( + "fmt" "io" "strings" ) @@ -102,13 +103,105 @@ func trimStrFunc(ctx ExprContext, name string, args []any) (result any, err erro return } +func startsWithStrFunc(ctx ExprContext, name string, args []any) (result any, err error) { + var source string + var ok bool + + result = false + if len(args) < 1 { + return result, errMissingRequiredParameter(name, paramSource) + } + if source, ok = args[0].(string); !ok { + return result, errWrongParamType(name, paramSource, typeString, args[0]) + } + for i, targetSpec := range args[1:] { + if target, ok := targetSpec.(string); ok { + if strings.HasPrefix(source, target) { + result = true + break + } + } else { + err = fmt.Errorf("target item nr %d is %T, expected string", i+1, targetSpec) + break + } + } + return +} + +func endsWithStrFunc(ctx ExprContext, name string, args []any) (result any, err error) { + var source string + var ok bool + + result = false + if len(args) < 1 { + return result, errMissingRequiredParameter(name, paramSource) + } + if source, ok = args[0].(string); !ok { + return result, errWrongParamType(name, paramSource, typeString, args[0]) + } + for i, targetSpec := range args[1:] { + if target, ok := targetSpec.(string); ok { + if strings.HasSuffix(source, target) { + result = true + break + } + } else { + err = fmt.Errorf("target item nr %d is %T, expected string", i+1, targetSpec) + break + } + } + return +} + +func splitStrFunc(ctx ExprContext, name string, args []any) (result any, err error) { + var source, sep string + var count int = -1 + var parts []string + var ok bool + + if len(args) < 1 { + return result, errMissingRequiredParameter(name, paramSource) + } + if source, ok = args[0].(string); !ok { + return result, errWrongParamType(name, paramSource, typeString, args[0]) + } + if len(args) >= 2 { + if sep, ok = args[1].(string); !ok { + return nil, fmt.Errorf("separator param must be string, got %T (%v)", args[1], args[1]) + } + if len(args) >= 3 { + if count64, ok := args[2].(int64); ok { // TODO replace type assertion with toInt() + count = int(count64) + } else { + return nil, fmt.Errorf("part count must be integer, got %T (%v)", args[2], args[2]) + } + } + } + if count > 0 { + parts = strings.SplitN(source, sep, count) + } else if count < 0 { + parts = strings.Split(source, sep) + } else { + parts = []string{} + } + list := make(ListType, len(parts)) + for i, part := range parts { + list[i] = part + } + result = &list + return +} + // --- End of function definitions // Import above functions in the context func ImportStringFuncs(ctx ExprContext) { ctx.RegisterFunc("joinStr", &simpleFunctor{f: joinStrFunc}, 1, -1) ctx.RegisterFunc("subStr", &simpleFunctor{f: subStrFunc}, 1, -1) + ctx.RegisterFunc("splitStr", &simpleFunctor{f: splitStrFunc}, 2, -1) ctx.RegisterFunc("trimStr", &simpleFunctor{f: trimStrFunc}, 1, -1) + ctx.RegisterFunc("startsWithStr", &simpleFunctor{f: startsWithStrFunc}, 2, -1) + ctx.RegisterFunc("endsWithStr", &simpleFunctor{f: endsWithStrFunc}, 2, -1) } // Register the import function in the import-register.