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:
parent
719e269cb1
commit
bb07fa15b7
3 changed files with 142 additions and 2 deletions
|
@ -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.
|
||||
|
|
131
stdlib/text.go
131
stdlib/text.go
|
@ -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
|
||||
|
|
|
@ -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+-+-+")
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue