add function SubStrRune/StrLimitRune/PosRune/PosIRune/PosRRune/PosRIRune for package gstr; remove unicode support in function SubStr/StrLimit for package gstr

This commit is contained in:
John
2020-04-07 23:51:48 +08:00
parent 25a91c732c
commit 90d751f98d
4 changed files with 215 additions and 17 deletions

View File

@ -158,9 +158,35 @@ func IsNumeric(s string) bool {
// SubStr returns a portion of string <str> specified by the <start> and <length> 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 <str> specified by the <start> and <length> parameters.
// SubStrRune considers parameter <str> 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 <str> specified by <length> parameters,
// if the length of <str> is greater than <length>,
// then the <suffix> will be appended to the result string.
// StrLimit returns a portion of string <str> specified by <length> parameters, if the length
// of <str> is greater than <length>, then the <suffix> 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 <str> specified by <length> parameters, if the length
// of <str> is greater than <length>, then the <suffix> will be appended to the result string.
// StrLimitRune considers parameter <str> 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 <body> and <end> 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 <str> 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 <str> 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 <str> 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 <str> to <hide> by <percentage> from the <middle>.
// It considers parameter <str> 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(<br>|<br />) before all newlines in a string:
// \n\r, \r\n, \r, \n.
// It considers parameter <str> as unicode string.
func Nl2Br(str string, isXhtml ...bool) string {
r, n, runes := '\r', '\n', []rune(str)
var br []byte

View File

@ -31,6 +31,15 @@ func Pos(haystack, needle string, startOffset ...int) int {
return pos + offset
}
// PosRune acts like function Pos but considers <haystack> and <needle> 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 <needle>
// in <haystack> from <startOffset>, 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 <haystack> and <needle> 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 <needle>
// in <haystack> from <startOffset>, 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 <haystack> and <needle> 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 <needle>
// in <haystack> from <startOffset>, 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 <haystack> and <needle> 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]))
}

View File

@ -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)

View File

@ -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)
})
}