diff --git a/CHANGELOG.md b/CHANGELOG.md index 66d6b37d..c9b8a43c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,10 +7,11 @@ Adding: - lo.RepeatBy -- lo.Substring - lo.Subset - lo.Replace - lo.ReplaceAll +- lo.Substring +- lo.RuneLength ## 1.18.0 (2022-04-28) diff --git a/README.md b/README.md index fd42654d..d99820d1 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,11 @@ Supported math helpers: - Range / RangeFrom / RangeWithSteps - Clamp +Supported helpers for strings: + +- Substring +- RuneLength + Supported helpers for tuples: - T2 -> T9 @@ -578,21 +583,6 @@ count := lo.CountBy[int]([]int{1, 5, 1}, func(i int) bool { // 2 ``` -### Substring - -Return part of a string. - -```go -sub := lo.Substring("hello", 2, 3) -// "llo" - -sub := lo.Substring("hello", -4, 3) -// "ell" - -sub := lo.Substring("hello", -2, math.MaxUint) -// "lo" -``` - ### Subset Return part of a slice. @@ -849,6 +839,33 @@ r3 := lo.Clamp(42, -10, 10) // 10 ``` +### Substring + +Return part of a string. + +```go +sub := lo.Substring("hello", 2, 3) +// "llo" + +sub := lo.Substring("hello", -4, 3) +// "ell" + +sub := lo.Substring("hello", -2, math.MaxUint) +// "lo" +``` + +### RuneLength + +An alias to utf8.RuneCountInString which returns the number of runes in string. + +```go +sub := lo.RuneLength("hellô") +// 5 + +sub := len("hellô") +// 6 +``` + ### T2 -> T9 Creates a tuple from a list of values. diff --git a/slice.go b/slice.go index 8b50e3b5..04d048be 100644 --- a/slice.go +++ b/slice.go @@ -363,28 +363,6 @@ func CountBy[T any](collection []T, predicate func(T) bool) (count int) { return count } -// Substring return part of a string. -func Substring[T ~string](str T, offset int, length uint) T { - size := len(str) - - if offset < 0 { - offset = size + offset - if offset < 0 { - offset = 0 - } - } - - if offset > size { - return Empty[T]() - } - - if length > uint(size)-uint(offset) { - length = uint(size - offset) - } - - return str[offset : offset+int(length)] -} - // Subset return part of a slice. func Subset[T any](collection []T, offset int, length uint) []T { size := len(collection) diff --git a/slice_test.go b/slice_test.go index c709f678..e5675805 100644 --- a/slice_test.go +++ b/slice_test.go @@ -384,36 +384,6 @@ func TestCountBy(t *testing.T) { is.Equal(count3, 0) } -func TestSubstring(t *testing.T) { - is := assert.New(t) - - str1 := Substring("hello", 0, 0) - str2 := Substring("hello", 10, 2) - str3 := Substring("hello", -10, 2) - str4 := Substring("hello", 0, 10) - str5 := Substring("hello", 0, 2) - str6 := Substring("hello", 2, 2) - str7 := Substring("hello", 2, 5) - str8 := Substring("hello", 2, 3) - str9 := Substring("hello", 2, 4) - str10 := Substring("hello", -2, 4) - str11 := Substring("hello", -4, 1) - str12 := Substring("hello", -4, math.MaxUint) - - is.Equal("", str1) - is.Equal("", str2) - is.Equal("he", str3) - is.Equal("hello", str4) - is.Equal("he", str5) - is.Equal("ll", str6) - is.Equal("llo", str7) - is.Equal("llo", str8) - is.Equal("llo", str9) - is.Equal("lo", str10) - is.Equal("e", str11) - is.Equal("ello", str12) -} - func TestSubset(t *testing.T) { is := assert.New(t) diff --git a/string.go b/string.go new file mode 100644 index 00000000..f60f764a --- /dev/null +++ b/string.go @@ -0,0 +1,30 @@ +package lo + +import "unicode/utf8" + +// Substring return part of a string. +func Substring[T ~string](str T, offset int, length uint) T { + size := len(str) + + if offset < 0 { + offset = size + offset + if offset < 0 { + offset = 0 + } + } + + if offset > size { + return Empty[T]() + } + + if length > uint(size)-uint(offset) { + length = uint(size - offset) + } + + return str[offset : offset+int(length)] +} + +// RuneLength is an alias to utf8.RuneCountInString which returns the number of runes in string. +func RuneLength(str string) int { + return utf8.RuneCountInString(str) +} diff --git a/string_test.go b/string_test.go new file mode 100644 index 00000000..cd0e7756 --- /dev/null +++ b/string_test.go @@ -0,0 +1,45 @@ +package lo + +import ( + "math" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestSubstring(t *testing.T) { + is := assert.New(t) + + str1 := Substring("hello", 0, 0) + str2 := Substring("hello", 10, 2) + str3 := Substring("hello", -10, 2) + str4 := Substring("hello", 0, 10) + str5 := Substring("hello", 0, 2) + str6 := Substring("hello", 2, 2) + str7 := Substring("hello", 2, 5) + str8 := Substring("hello", 2, 3) + str9 := Substring("hello", 2, 4) + str10 := Substring("hello", -2, 4) + str11 := Substring("hello", -4, 1) + str12 := Substring("hello", -4, math.MaxUint) + + is.Equal("", str1) + is.Equal("", str2) + is.Equal("he", str3) + is.Equal("hello", str4) + is.Equal("he", str5) + is.Equal("ll", str6) + is.Equal("llo", str7) + is.Equal("llo", str8) + is.Equal("llo", str9) + is.Equal("lo", str10) + is.Equal("e", str11) + is.Equal("ello", str12) +} + +func TestRuneLength(t *testing.T) { + is := assert.New(t) + + is.Equal(5, RuneLength("hellô")) + is.Equal(6, len("hellô")) +}