text.trim, text.pad_left and text.pad_right (#183)

* Added trim, pad_left and pad_right to text

* Check MaxStringLen

* Added doc

* Fixed doc

* Moved length check
This commit is contained in:
earncef 2019-04-11 09:23:30 +02:00 committed by Daniel
parent 719e269cb1
commit bb07fa15b7
3 changed files with 142 additions and 2 deletions

View file

@ -26,6 +26,7 @@ text := import("text")
- `last_index_any(s string, chars string) => int`: returns the index of the last instance of any Unicode code point from chars in s, or -1 if no Unicode code point from chars is present in s.
- `repeat(s string, count int) => string`: returns a new string consisting of count copies of the string s.
- `replace(s string, old string, new string, n int) => string`: returns a copy of the string s with the first n non-overlapping instances of old replaced by new.
- `substr(s string, lower int, upper int) => string => string`: returns a substring of the string s specified by the lower and upper parameters.
- `split(s string, sep string) => [string]`: slices s into all substrings separated by sep and returns a slice of the substrings between those separators.
- `split_after(s string, sep string) => [string]`: slices s into all substrings after each instance of sep and returns a slice of those substrings.
- `split_after_n(s string, sep string, n int) => [string]`: slices s into substrings after each instance of sep and returns a slice of those substrings.
@ -34,6 +35,9 @@ text := import("text")
- `to_lower(s string) => string`: returns a copy of the string s with all Unicode letters mapped to their lower case.
- `to_title(s string) => string`: returns a copy of the string s with all Unicode letters mapped to their title case.
- `to_upper(s string) => string`: returns a copy of the string s with all Unicode letters mapped to their upper case.
- `pad_left(s string, pad_len int, pad_with string) => string`: returns a copy of the string s padded on the left with the contents of the string pad_with to length pad_len. If pad_with is not specified, white space is used as the default padding.
- `pad_right(s string, pad_len int, pad_with string) => string`: returns a copy of the string s padded on the right with the contents of the string pad_with to length pad_len. If pad_with is not specified, white space is used as the default padding.
- `trim(s string, cutset string) => string`: returns a slice of the string s with all leading and trailing Unicode code points contained in cutset removed.
- `trim_left(s string, cutset string) => string`: returns a slice of the string s with all leading Unicode code points contained in cutset removed.
- `trim_prefix(s string, prefix string) => string`: returns s without the provided leading prefix string.
- `trim_right(s string, cutset string) => string`: returns a slice of the string s, with all trailing Unicode code points contained in cutset removed.
@ -55,4 +59,4 @@ text := import("text")
- `match(text string) => bool`: reports whether the string s contains any match of the regular expression pattern.
- `find(text string, count int) => [[{text: string, begin: int, end: int}]]/undefined`: returns an array holding all matches, each of which is an array of map object that contains matching text, begin and end (exclusive) index.
- `replace(src string, repl string) => string`: returns a copy of src, replacing matches of the pattern with the replacement string repl.
- `split(text string, count int) => [string]`: slices s into substrings separated by the expression and returns a slice of the substrings between those expression matches.
- `split(text string, count int) => [string]`: slices s into substrings separated by the expression and returns a slice of the substrings between those expression matches.

View file

@ -32,7 +32,7 @@ var textModule = map[string]objects.Object{
"last_index_any": &objects.UserFunction{Name: "last_index_any", Value: FuncASSRI(strings.LastIndexAny)}, // last_index_any(s, chars) => int
"repeat": &objects.UserFunction{Name: "repeat", Value: textRepeat}, // repeat(s, count) => string
"replace": &objects.UserFunction{Name: "replace", Value: textReplace}, // replace(s, old, new, n) => string
"substr": &objects.UserFunction{Name: "substr", Value: textSubstring}, // substring(s, lower, upper) => string
"substr": &objects.UserFunction{Name: "substr", Value: textSubstring}, // substr(s, lower, upper) => string
"split": &objects.UserFunction{Name: "split", Value: FuncASSRSs(strings.Split)}, // split(s, sep) => [string]
"split_after": &objects.UserFunction{Name: "split_after", Value: FuncASSRSs(strings.SplitAfter)}, // split_after(s, sep) => [string]
"split_after_n": &objects.UserFunction{Name: "split_after_n", Value: FuncASSIRSs(strings.SplitAfterN)}, // split_after_n(s, sep, n) => [string]
@ -41,6 +41,9 @@ var textModule = map[string]objects.Object{
"to_lower": &objects.UserFunction{Name: "to_lower", Value: FuncASRS(strings.ToLower)}, // to_lower(s) => string
"to_title": &objects.UserFunction{Name: "to_title", Value: FuncASRS(strings.ToTitle)}, // to_title(s) => string
"to_upper": &objects.UserFunction{Name: "to_upper", Value: FuncASRS(strings.ToUpper)}, // to_upper(s) => string
"pad_left": &objects.UserFunction{Name: "pad_left", Value: textPadLeft}, // pad_left(s, pad_len, pad_with) => string
"pad_right": &objects.UserFunction{Name: "pad_right", Value: textPadRight}, // pad_right(s, pad_len, pad_with) => string
"trim": &objects.UserFunction{Name: "trim", Value: FuncASSRS(strings.Trim)}, // trim(s, cutset) => string
"trim_left": &objects.UserFunction{Name: "trim_left", Value: FuncASSRS(strings.TrimLeft)}, // trim_left(s, cutset) => string
"trim_prefix": &objects.UserFunction{Name: "trim_prefix", Value: FuncASSRS(strings.TrimPrefix)}, // trim_prefix(s, prefix) => string
"trim_right": &objects.UserFunction{Name: "trim_right", Value: FuncASSRS(strings.TrimRight)}, // trim_right(s, cutset) => string
@ -440,6 +443,132 @@ func textSubstring(args ...objects.Object) (ret objects.Object, err error) {
return
}
func textPadLeft(args ...objects.Object) (ret objects.Object, err error) {
argslen := len(args)
if argslen != 2 && argslen != 3 {
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
}
i2, ok := objects.ToInt(args[1])
if !ok {
err = objects.ErrInvalidArgumentType{
Name: "second",
Expected: "int(compatible)",
Found: args[1].TypeName(),
}
return
}
if i2 > tengo.MaxStringLen {
return nil, objects.ErrStringLimit
}
sLen := len(s1)
if sLen >= i2 {
ret = &objects.String{Value: s1}
return
}
s3 := " "
if argslen == 3 {
s3, ok = objects.ToString(args[2])
if !ok {
err = objects.ErrInvalidArgumentType{
Name: "third",
Expected: "string(compatible)",
Found: args[2].TypeName(),
}
return
}
}
padStrLen := len(s3)
if padStrLen == 0 {
ret = &objects.String{Value: s1}
return
}
padCount := ((i2 - padStrLen) / padStrLen) + 1
retStr := strings.Repeat(s3, int(padCount)) + s1
ret = &objects.String{Value: retStr[len(retStr)-i2:]}
return
}
func textPadRight(args ...objects.Object) (ret objects.Object, err error) {
argslen := len(args)
if argslen != 2 && argslen != 3 {
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
}
i2, ok := objects.ToInt(args[1])
if !ok {
err = objects.ErrInvalidArgumentType{
Name: "second",
Expected: "int(compatible)",
Found: args[1].TypeName(),
}
return
}
if i2 > tengo.MaxStringLen {
return nil, objects.ErrStringLimit
}
sLen := len(s1)
if sLen >= i2 {
ret = &objects.String{Value: s1}
return
}
s3 := " "
if argslen == 3 {
s3, ok = objects.ToString(args[2])
if !ok {
err = objects.ErrInvalidArgumentType{
Name: "third",
Expected: "string(compatible)",
Found: args[2].TypeName(),
}
return
}
}
padStrLen := len(s3)
if padStrLen == 0 {
ret = &objects.String{Value: s1}
return
}
padCount := ((i2 - padStrLen) / padStrLen) + 1
retStr := s1 + strings.Repeat(s3, int(padCount))
ret = &objects.String{Value: retStr[:i2]}
return
}
func textRepeat(args ...objects.Object) (ret objects.Object, err error) {
if len(args) != 2 {
return nil, objects.ErrWrongNumArguments

View file

@ -263,3 +263,10 @@ func TestSubstr(t *testing.T) {
module(t, "text").call("substr", 123, 0, 1).expect("1")
module(t, "text").call("substr", 123.456, 4, 7).expect("456")
}
func TestPadLeft(t *testing.T) {
module(t, "text").call("pad_left", "ab", 7, 0).expect("00000ab")
module(t, "text").call("pad_right", "ab", 7, 0).expect("ab00000")
module(t, "text").call("pad_left", "ab", 7, "+-").expect("-+-+-ab")
module(t, "text").call("pad_right", "ab", 7, "+-").expect("ab+-+-+")
}