From 90d751f98dcbf5451511d332ebcdda3b511809bc Mon Sep 17 00:00:00 2001 From: John Date: Tue, 7 Apr 2020 23:51:48 +0800 Subject: [PATCH] add function SubStrRune/StrLimitRune/PosRune/PosIRune/PosRRune/PosRIRune for package gstr; remove unicode support in function SubStr/StrLimit for package gstr --- text/gstr/gstr.go | 69 +++++++++++++++++---- text/gstr/gstr_pos.go | 36 +++++++++++ text/gstr/gstr_z_unit_basic_test.go | 32 ++++++++-- text/gstr/gstr_z_unit_pos_test.go | 95 +++++++++++++++++++++++++++++ 4 files changed, 215 insertions(+), 17 deletions(-) diff --git a/text/gstr/gstr.go b/text/gstr/gstr.go index e225f423a..c82fe6638 100644 --- a/text/gstr/gstr.go +++ b/text/gstr/gstr.go @@ -158,9 +158,35 @@ func IsNumeric(s string) bool { // SubStr returns a portion of string specified by the and parameters. func SubStr(str string, start int, length ...int) (substr string) { + lth := len(str) + + // Simple border checks. + if start < 0 { + start = 0 + } + if start >= lth { + start = lth + } + end := lth + if len(length) > 0 { + end = start + length[0] + if end < start { + end = lth + } + } + if end > lth { + end = lth + } + return str[start:end] +} + +// SubStrRune returns a portion of string specified by the and parameters. +// SubStrRune considers parameter as unicode string. +func SubStrRune(str string, start int, length ...int) (substr string) { // Converting to []rune to support unicode. rs := []rune(str) lth := len(rs) + // Simple border checks. if start < 0 { start = 0 @@ -181,10 +207,23 @@ func SubStr(str string, start int, length ...int) (substr string) { return string(rs[start:end]) } -// StrLimit returns a portion of string specified by parameters, -// if the length of is greater than , -// then the will be appended to the result string. +// StrLimit returns a portion of string specified by parameters, if the length +// of is greater than , then the will be appended to the result string. func StrLimit(str string, length int, suffix ...string) string { + if len(str) < length { + return str + } + addStr := "..." + if len(suffix) > 0 { + addStr = suffix[0] + } + return str[0:length] + addStr +} + +// StrLimitRune returns a portion of string specified by parameters, if the length +// of is greater than , then the will be appended to the result string. +// StrLimitRune considers parameter as unicode string. +func StrLimitRune(str string, length int, suffix ...string) string { rs := []rune(str) if len(rs) < length { return str @@ -255,6 +294,7 @@ func NumberFormat(number float64, decimals int, decPoint, thousandsSep string) s // Can be used to split a string into smaller chunks which is useful for // e.g. converting BASE64 string output to match RFC 2045 semantics. // It inserts end every chunkLen characters. +// It considers parameter and as unicode string. func ChunkSplit(body string, chunkLen int, end string) string { if end == "" { end = "\r\n" @@ -304,6 +344,7 @@ func HasSuffix(s, suffix string) bool { } // CountWords returns information about words' count used in a string. +// It considers parameter as unicode string. func CountWords(str string) map[string]int { m := make(map[string]int) buffer := bytes.NewBuffer(nil) @@ -324,6 +365,7 @@ func CountWords(str string) map[string]int { } // CountChars returns information about chars' count used in a string. +// It considers parameter as unicode string. func CountChars(str string, noSpace ...bool) map[string]int { m := make(map[string]int) countSpace := true @@ -423,6 +465,7 @@ func Str(haystack string, needle string) string { } // Shuffle randomly shuffles a string. +// It considers parameter as unicode string. func Shuffle(str string) string { runes := []rune(str) s := make([]rune, len(runes)) @@ -502,19 +545,22 @@ func Ord(char string) int { } // HideStr replaces part of the the string to by from the . +// It considers parameter as unicode string. func HideStr(str string, percent int, hide string) string { array := strings.Split(str, "@") if len(array) > 1 { str = array[0] } - rs := []rune(str) - length := len(rs) - mid := math.Floor(float64(length / 2)) - hideLen := int(math.Floor(float64(length) * (float64(percent) / 100))) - start := int(mid - math.Floor(float64(hideLen)/2)) - hideStr := []rune("") - hideRune := []rune(hide) - for i := 0; i < int(hideLen); i++ { + var ( + rs = []rune(str) + length = len(rs) + mid = math.Floor(float64(length / 2)) + hideLen = int(math.Floor(float64(length) * (float64(percent) / 100))) + start = int(mid - math.Floor(float64(hideLen)/2)) + hideStr = []rune("") + hideRune = []rune(hide) + ) + for i := 0; i < hideLen; i++ { hideStr = append(hideStr, hideRune...) } buffer := bytes.NewBuffer(nil) @@ -529,6 +575,7 @@ func HideStr(str string, percent int, hide string) string { // Nl2Br inserts HTML line breaks(
|
) before all newlines in a string: // \n\r, \r\n, \r, \n. +// It considers parameter as unicode string. func Nl2Br(str string, isXhtml ...bool) string { r, n, runes := '\r', '\n', []rune(str) var br []byte diff --git a/text/gstr/gstr_pos.go b/text/gstr/gstr_pos.go index 8a55bc89f..bf76e756a 100644 --- a/text/gstr/gstr_pos.go +++ b/text/gstr/gstr_pos.go @@ -31,6 +31,15 @@ func Pos(haystack, needle string, startOffset ...int) int { return pos + offset } +// PosRune acts like function Pos but considers and as unicode string. +func PosRune(haystack, needle string, startOffset ...int) int { + pos := Pos(haystack, needle, startOffset...) + if pos < 3 { + return pos + } + return len([]rune(haystack[:pos])) +} + // PosI returns the position of the first occurrence of // in from , case-insensitively. // It returns -1, if not found. @@ -54,6 +63,15 @@ func PosI(haystack, needle string, startOffset ...int) int { return pos + offset } +// PosIRune acts like function PosI but considers and as unicode string. +func PosIRune(haystack, needle string, startOffset ...int) int { + pos := PosI(haystack, needle, startOffset...) + if pos < 3 { + return pos + } + return len([]rune(haystack[:pos])) +} + // PosR returns the position of the last occurrence of // in from , case-sensitively. // It returns -1, if not found. @@ -79,6 +97,15 @@ func PosR(haystack, needle string, startOffset ...int) int { return pos } +// PosRRune acts like function PosR but considers and as unicode string. +func PosRRune(haystack, needle string, startOffset ...int) int { + pos := PosR(haystack, needle, startOffset...) + if pos < 3 { + return pos + } + return len([]rune(haystack[:pos])) +} + // PosRI returns the position of the last occurrence of // in from , case-insensitively. // It returns -1, if not found. @@ -103,3 +130,12 @@ func PosRI(haystack, needle string, startOffset ...int) int { } return pos } + +// PosRIRune acts like function PosRI but considers and as unicode string. +func PosRIRune(haystack, needle string, startOffset ...int) int { + pos := PosRI(haystack, needle, startOffset...) + if pos < 3 { + return pos + } + return len([]rune(haystack[:pos])) +} diff --git a/text/gstr/gstr_z_unit_basic_test.go b/text/gstr/gstr_z_unit_basic_test.go index d283f3a5c..24a322de7 100644 --- a/text/gstr/gstr_z_unit_basic_test.go +++ b/text/gstr/gstr_z_unit_basic_test.go @@ -137,23 +137,43 @@ func Test_IsNumeric(t *testing.T) { func Test_SubStr(t *testing.T) { gtest.C(t, func(t *gtest.T) { t.Assert(gstr.SubStr("我爱GoFrame", 0), "我爱GoFrame") - t.Assert(gstr.SubStr("我爱GoFrame", 2), "GoFrame") - t.Assert(gstr.SubStr("我爱GoFrame", 2, 2), "Go") + t.Assert(gstr.SubStr("我爱GoFrame", 6), "GoFrame") + t.Assert(gstr.SubStr("我爱GoFrame", 6, 2), "Go") t.Assert(gstr.SubStr("我爱GoFrame", -1, 30), "我爱GoFrame") t.Assert(gstr.SubStr("我爱GoFrame", 30, 30), "") }) } +func Test_SubStrRune(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + t.Assert(gstr.SubStrRune("我爱GoFrame", 0), "我爱GoFrame") + t.Assert(gstr.SubStrRune("我爱GoFrame", 2), "GoFrame") + t.Assert(gstr.SubStrRune("我爱GoFrame", 2, 2), "Go") + t.Assert(gstr.SubStrRune("我爱GoFrame", -1, 30), "我爱GoFrame") + t.Assert(gstr.SubStrRune("我爱GoFrame", 30, 30), "") + }) +} + func Test_StrLimit(t *testing.T) { gtest.C(t, func(t *gtest.T) { - t.Assert(gstr.StrLimit("我爱GoFrame", 2), "我爱...") - t.Assert(gstr.StrLimit("我爱GoFrame", 2, ""), "我爱") - t.Assert(gstr.StrLimit("我爱GoFrame", 2, "**"), "我爱**") - t.Assert(gstr.StrLimit("我爱GoFrame", 4, ""), "我爱Go") + t.Assert(gstr.StrLimit("我爱GoFrame", 6), "我爱...") + t.Assert(gstr.StrLimit("我爱GoFrame", 6, ""), "我爱") + t.Assert(gstr.StrLimit("我爱GoFrame", 6, "**"), "我爱**") + t.Assert(gstr.StrLimit("我爱GoFrame", 8, ""), "我爱Go") t.Assert(gstr.StrLimit("*", 4, ""), "*") }) } +func Test_StrLimitRune(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + t.Assert(gstr.StrLimitRune("我爱GoFrame", 2), "我爱...") + t.Assert(gstr.StrLimitRune("我爱GoFrame", 2, ""), "我爱") + t.Assert(gstr.StrLimitRune("我爱GoFrame", 2, "**"), "我爱**") + t.Assert(gstr.StrLimitRune("我爱GoFrame", 4, ""), "我爱Go") + t.Assert(gstr.StrLimitRune("*", 4, ""), "*") + }) +} + func Test_HasPrefix(t *testing.T) { gtest.C(t, func(t *gtest.T) { t.Assert(gstr.HasPrefix("我爱GoFrame", "我爱"), true) diff --git a/text/gstr/gstr_z_unit_pos_test.go b/text/gstr/gstr_z_unit_pos_test.go index fdd4edecc..68288f3cf 100644 --- a/text/gstr/gstr_z_unit_pos_test.go +++ b/text/gstr/gstr_z_unit_pos_test.go @@ -23,6 +23,28 @@ func Test_Pos(t *testing.T) { t.Assert(gstr.Pos(s1, "abd", 0), -1) t.Assert(gstr.Pos(s1, "e", -4), 11) }) + gtest.C(t, func(t *gtest.T) { + s1 := "我爱China very much" + t.Assert(gstr.Pos(s1, "爱"), 3) + t.Assert(gstr.Pos(s1, "C"), 6) + t.Assert(gstr.Pos(s1, "China"), 6) + }) +} + +func Test_PosRune(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + s1 := "abcdEFGabcdefg" + t.Assert(gstr.PosRune(s1, "ab"), 0) + t.Assert(gstr.PosRune(s1, "ab", 2), 7) + t.Assert(gstr.PosRune(s1, "abd", 0), -1) + t.Assert(gstr.PosRune(s1, "e", -4), 11) + }) + gtest.C(t, func(t *gtest.T) { + s1 := "我爱China very much" + t.Assert(gstr.PosRune(s1, "爱"), 1) + t.Assert(gstr.PosRune(s1, "C"), 2) + t.Assert(gstr.PosRune(s1, "China"), 2) + }) } func Test_PosI(t *testing.T) { @@ -34,6 +56,29 @@ func Test_PosI(t *testing.T) { t.Assert(gstr.PosI(s1, "abd", 0), -1) t.Assert(gstr.PosI(s1, "E", -4), 11) }) + gtest.C(t, func(t *gtest.T) { + s1 := "我爱China very much" + t.Assert(gstr.PosI(s1, "爱"), 3) + t.Assert(gstr.PosI(s1, "c"), 6) + t.Assert(gstr.PosI(s1, "china"), 6) + }) +} + +func Test_PosIRune(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + s1 := "abcdEFGabcdefg" + t.Assert(gstr.PosIRune(s1, "zz"), -1) + t.Assert(gstr.PosIRune(s1, "ab"), 0) + t.Assert(gstr.PosIRune(s1, "ef", 2), 4) + t.Assert(gstr.PosIRune(s1, "abd", 0), -1) + t.Assert(gstr.PosIRune(s1, "E", -4), 11) + }) + gtest.C(t, func(t *gtest.T) { + s1 := "我爱China very much" + t.Assert(gstr.PosIRune(s1, "爱"), 1) + t.Assert(gstr.PosIRune(s1, "c"), 2) + t.Assert(gstr.PosIRune(s1, "china"), 2) + }) } func Test_PosR(t *testing.T) { @@ -47,6 +92,31 @@ func Test_PosR(t *testing.T) { t.Assert(gstr.PosR(s1, "abd", 0), -1) t.Assert(gstr.PosR(s1, "e", -4), -1) }) + gtest.C(t, func(t *gtest.T) { + s1 := "我爱China very much" + t.Assert(gstr.PosR(s1, "爱"), 3) + t.Assert(gstr.PosR(s1, "C"), 6) + t.Assert(gstr.PosR(s1, "China"), 6) + }) +} + +func Test_PosRRune(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + s1 := "abcdEFGabcdefg" + s2 := "abcdEFGz1cdeab" + t.Assert(gstr.PosRRune(s1, "zz"), -1) + t.Assert(gstr.PosRRune(s1, "ab"), 7) + t.Assert(gstr.PosRRune(s2, "ab", -2), 0) + t.Assert(gstr.PosRRune(s1, "ef"), 11) + t.Assert(gstr.PosRRune(s1, "abd", 0), -1) + t.Assert(gstr.PosRRune(s1, "e", -4), -1) + }) + gtest.C(t, func(t *gtest.T) { + s1 := "我爱China very much" + t.Assert(gstr.PosRRune(s1, "爱"), 1) + t.Assert(gstr.PosRRune(s1, "C"), 2) + t.Assert(gstr.PosRRune(s1, "China"), 2) + }) } func Test_PosRI(t *testing.T) { @@ -60,4 +130,29 @@ func Test_PosRI(t *testing.T) { t.Assert(gstr.PosRI(s1, "abd", 0), -1) t.Assert(gstr.PosRI(s1, "e", -5), 4) }) + gtest.C(t, func(t *gtest.T) { + s1 := "我爱China very much" + t.Assert(gstr.PosRI(s1, "爱"), 3) + t.Assert(gstr.PosRI(s1, "C"), 19) + t.Assert(gstr.PosRI(s1, "China"), 6) + }) +} + +func Test_PosRIRune(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + s1 := "abcdEFGabcdefg" + s2 := "abcdEFGz1cdeab" + t.Assert(gstr.PosRIRune(s1, "zz"), -1) + t.Assert(gstr.PosRIRune(s1, "AB"), 7) + t.Assert(gstr.PosRIRune(s2, "AB", -2), 0) + t.Assert(gstr.PosRIRune(s1, "EF"), 11) + t.Assert(gstr.PosRIRune(s1, "abd", 0), -1) + t.Assert(gstr.PosRIRune(s1, "e", -5), 4) + }) + gtest.C(t, func(t *gtest.T) { + s1 := "我爱China very much" + t.Assert(gstr.PosRIRune(s1, "爱"), 1) + t.Assert(gstr.PosRIRune(s1, "C"), 15) + t.Assert(gstr.PosRIRune(s1, "China"), 2) + }) }