diff --git a/pkg/stdlib/strings/like.go b/pkg/stdlib/strings/like.go index c463967f..b0463196 100644 --- a/pkg/stdlib/strings/like.go +++ b/pkg/stdlib/strings/like.go @@ -2,12 +2,18 @@ package strings import ( "context" + "unicode" + "github.com/MontFerret/ferret/pkg/runtime/core" "github.com/MontFerret/ferret/pkg/runtime/values" ) /* * Checks whether the pattern search is contained in the string text, using wildcard matching. + * @param text (String) - The string to search in. + * @param search (String) - A search pattern that can contain the wildcard characters. + * @param caseInsensitive (Boolean) - If set to true, the matching will be case-insensitive. The default is false. + * @return (Boolean) - Returns true if the pattern is contained in text, and false otherwise. */ func Like(_ context.Context, args ...core.Value) (core.Value, error) { err := core.ValidateArgs(args, 2, 3) @@ -16,5 +22,44 @@ func Like(_ context.Context, args ...core.Value) (core.Value, error) { return values.False, err } - return values.None, core.Error(core.ErrNotImplemented, "LIKE") + str := []rune(args[0].String()) + pattern := []rune(args[1].String()) + + if len(pattern) == 0 { + return values.NewBoolean(len(str) == 0), nil + } + + lookup := make([][]bool, len(str)+1) + + for i := range lookup { + lookup[i] = make([]bool, len(pattern)+1) + } + + lookup[0][0] = true + + for j := 1; j < len(pattern)+1; j++ { + if pattern[j-1] == '%' { + lookup[0][j] = lookup[0][j-1] + } + } + + for i := 1; i < len(str)+1; i++ { + for j := 1; j < len(pattern)+1; j++ { + if pattern[j-1] == '%' { + lookup[i][j] = lookup[i][j-1] || lookup[i-1][j] + } else if pattern[j-1] == '_' || str[i-1] == pattern[j-1] { + lookup[i][j] = lookup[i-1][j-1] + } else if len(args) > 2 { + if args[2] == values.True && unicode.ToLower(str[i-1]) == unicode.ToLower(pattern[j-1]) { + lookup[i][j] = lookup[i-1][j-1] + } + } else { + lookup[i][j] = false + } + } + } + + matched := lookup[len(str)][len(pattern)] + + return values.NewBoolean(matched), nil }