add string utils
This commit is contained in:
parent
c9848509b4
commit
d82220a8e1
296
pkg/strutil/string.go
Normal file
296
pkg/strutil/string.go
Normal file
@ -0,0 +1,296 @@
|
||||
// Package strutil 实现了一些函数来操作字符串
|
||||
package strutil
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// CamelCase 转换字符串到驼峰法(CamelCase)
|
||||
func CamelCase(s string) string {
|
||||
if len(s) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
res := ""
|
||||
blankSpace := " "
|
||||
regex, _ := regexp.Compile("[-_&]+")
|
||||
ss := regex.ReplaceAllString(s, blankSpace)
|
||||
for i, v := range strings.Split(ss, blankSpace) {
|
||||
vv := []rune(v)
|
||||
if i == 0 {
|
||||
if vv[i] >= 65 && vv[i] <= 96 {
|
||||
vv[0] += 32
|
||||
}
|
||||
res += string(vv)
|
||||
} else {
|
||||
res += Capitalize(v)
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// Capitalize 将一个字符串的第一个字符转换为大写,其余的转换为小写
|
||||
func Capitalize(s string) string {
|
||||
if len(s) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
out := make([]rune, len(s))
|
||||
for i, v := range s {
|
||||
if i == 0 {
|
||||
out[i] = unicode.ToUpper(v)
|
||||
} else {
|
||||
out[i] = unicode.ToLower(v)
|
||||
}
|
||||
}
|
||||
|
||||
return string(out)
|
||||
}
|
||||
|
||||
// UpperFirst 将字符串的第一个字符转换为大写
|
||||
func UpperFirst(s string) string {
|
||||
if len(s) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
r, size := utf8.DecodeRuneInString(s)
|
||||
r = unicode.ToUpper(r)
|
||||
|
||||
return string(r) + s[size:]
|
||||
}
|
||||
|
||||
// LowerFirst 将字符串的第一个字符转换为小写
|
||||
func LowerFirst(s string) string {
|
||||
if len(s) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
r, size := utf8.DecodeRuneInString(s)
|
||||
r = unicode.ToLower(r)
|
||||
|
||||
return string(r) + s[size:]
|
||||
}
|
||||
|
||||
// PadEnd 如果字符串比尺寸短,则将其垫在右侧
|
||||
// 填充字符如果超过大小,将被截断
|
||||
func PadEnd(source string, size int, padStr string) string {
|
||||
len1 := len(source)
|
||||
len2 := len(padStr)
|
||||
|
||||
if len1 >= size {
|
||||
return source
|
||||
}
|
||||
|
||||
fill := ""
|
||||
if len2 >= size-len1 {
|
||||
fill = padStr[0 : size-len1]
|
||||
} else {
|
||||
fill = strings.Repeat(padStr, size-len1)
|
||||
}
|
||||
return source + fill[0:size-len1]
|
||||
}
|
||||
|
||||
// PadStart 如果字符串比尺寸短,则将其垫在左侧
|
||||
//填充字符如果超过大小,将被截断
|
||||
func PadStart(source string, size int, padStr string) string {
|
||||
len1 := len(source)
|
||||
len2 := len(padStr)
|
||||
|
||||
if len1 >= size {
|
||||
return source
|
||||
}
|
||||
|
||||
fill := ""
|
||||
if len2 >= size-len1 {
|
||||
fill = padStr[0 : size-len1]
|
||||
} else {
|
||||
fill = strings.Repeat(padStr, size-len1)
|
||||
}
|
||||
return fill[0:size-len1] + source
|
||||
}
|
||||
|
||||
// KebabCase 将字符串转为短横线隔开式(kebab-case)
|
||||
func KebabCase(s string) string {
|
||||
if len(s) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
regex := regexp.MustCompile(`[\W|_]+`)
|
||||
blankSpace := " "
|
||||
match := regex.ReplaceAllString(s, blankSpace)
|
||||
rs := strings.Split(match, blankSpace)
|
||||
|
||||
var res []string
|
||||
for _, v := range rs {
|
||||
splitWords := splitWordsToLower(v)
|
||||
if len(splitWords) > 0 {
|
||||
res = append(res, splitWords...)
|
||||
}
|
||||
}
|
||||
|
||||
return strings.Join(res, "-")
|
||||
}
|
||||
|
||||
// SnakeCase 将字符串转为蛇形命名(snake_case)
|
||||
func SnakeCase(s string) string {
|
||||
if len(s) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
regex := regexp.MustCompile(`[\W|_]+`)
|
||||
blankSpace := " "
|
||||
match := regex.ReplaceAllString(s, blankSpace)
|
||||
rs := strings.Split(match, blankSpace)
|
||||
|
||||
var res []string
|
||||
for _, v := range rs {
|
||||
splitWords := splitWordsToLower(v)
|
||||
if len(splitWords) > 0 {
|
||||
res = append(res, splitWords...)
|
||||
}
|
||||
}
|
||||
|
||||
return strings.Join(res, "_")
|
||||
}
|
||||
|
||||
// Before 在字符首次出现的位置之前,在源字符串中创建子串
|
||||
func Before(s, char string) string {
|
||||
if s == "" || char == "" {
|
||||
return s
|
||||
}
|
||||
i := strings.Index(s, char)
|
||||
return s[0:i]
|
||||
}
|
||||
|
||||
// BeforeLast 在字符最后出现的位置之前,在源字符串中创建子串
|
||||
func BeforeLast(s, char string) string {
|
||||
if s == "" || char == "" {
|
||||
return s
|
||||
}
|
||||
i := strings.LastIndex(s, char)
|
||||
return s[0:i]
|
||||
}
|
||||
|
||||
// After 在字符首次出现的位置后,在源字符串中创建子串
|
||||
func After(s, char string) string {
|
||||
if s == "" || char == "" {
|
||||
return s
|
||||
}
|
||||
i := strings.Index(s, char)
|
||||
return s[i+len(char):]
|
||||
}
|
||||
|
||||
// AfterLast 在字符最后出现的位置后,在源字符串中创建子串
|
||||
func AfterLast(s, char string) string {
|
||||
if s == "" || char == "" {
|
||||
return s
|
||||
}
|
||||
i := strings.LastIndex(s, char)
|
||||
return s[i+len(char):]
|
||||
}
|
||||
|
||||
// IsString 检查值的数据类型是否为字符串
|
||||
func IsString(v any) bool {
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
switch v.(type) {
|
||||
case string:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// ReverseStr 返回字符顺序与给定字符串相反的字符串
|
||||
func ReverseStr(s string) string {
|
||||
r := []rune(s)
|
||||
for i, j := 0, len(r)-1; i < j; i, j = i+1, j-1 {
|
||||
r[i], r[j] = r[j], r[i]
|
||||
}
|
||||
return string(r)
|
||||
}
|
||||
|
||||
// Wrap 用另一个字符串包住一个字符串
|
||||
func Wrap(str string, wrapWith string) string {
|
||||
if str == "" || wrapWith == "" {
|
||||
return str
|
||||
}
|
||||
var sb strings.Builder
|
||||
sb.WriteString(wrapWith)
|
||||
sb.WriteString(str)
|
||||
sb.WriteString(wrapWith)
|
||||
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
// Unwrap 从另一个字符串中解开一个给定的字符串,将改变str值
|
||||
func Unwrap(str string, wrapToken string) string {
|
||||
if str == "" || wrapToken == "" {
|
||||
return str
|
||||
}
|
||||
|
||||
firstIndex := strings.Index(str, wrapToken)
|
||||
lastIndex := strings.LastIndex(str, wrapToken)
|
||||
|
||||
if firstIndex == 0 && lastIndex > 0 && lastIndex <= len(str)-1 {
|
||||
if len(wrapToken) <= lastIndex {
|
||||
str = str[len(wrapToken):lastIndex]
|
||||
}
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
// RemoveHTML 去除字符串中的 html, js
|
||||
func RemoveHTML(str string) string {
|
||||
if len(str) > 0 {
|
||||
//删除脚本
|
||||
reg := regexp.MustCompile(`([\r\n])[\s]+`)
|
||||
str = reg.ReplaceAllString(str, "")
|
||||
reg = regexp.MustCompile(`<script[^>]*?>.*?</script>`)
|
||||
str = reg.ReplaceAllString(str, "")
|
||||
//删除HTML
|
||||
reg = regexp.MustCompile(`<(.[^>]*)>`)
|
||||
str = reg.ReplaceAllString(str, "")
|
||||
reg = regexp.MustCompile(`([\r\n])[\s]+`)
|
||||
str = reg.ReplaceAllString(str, "")
|
||||
reg = regexp.MustCompile(`-->`)
|
||||
str = reg.ReplaceAllString(str, "")
|
||||
reg = regexp.MustCompile(`<!--.*`)
|
||||
str = reg.ReplaceAllString(str, "")
|
||||
reg = regexp.MustCompile(`&(quot|#34);`)
|
||||
str = reg.ReplaceAllString(str, "")
|
||||
reg = regexp.MustCompile(`&(amp|#38);`)
|
||||
str = reg.ReplaceAllString(str, "")
|
||||
reg = regexp.MustCompile(`&(lt|#60);`)
|
||||
str = reg.ReplaceAllString(str, "")
|
||||
reg = regexp.MustCompile(`&(gt|#62);`)
|
||||
str = reg.ReplaceAllString(str, "")
|
||||
reg = regexp.MustCompile(`&(nbsp|#160);`)
|
||||
str = reg.ReplaceAllString(str, "")
|
||||
reg = regexp.MustCompile(`&(iexcl|#161);`)
|
||||
str = reg.ReplaceAllString(str, "")
|
||||
reg = regexp.MustCompile(`&(cent|#162);`)
|
||||
str = reg.ReplaceAllString(str, "")
|
||||
reg = regexp.MustCompile(`&(pound|#163);`)
|
||||
str = reg.ReplaceAllString(str, "")
|
||||
reg = regexp.MustCompile(`&(copy|#169);`)
|
||||
str = reg.ReplaceAllString(str, "")
|
||||
reg = regexp.MustCompile(`&#(\d+);`)
|
||||
str = reg.ReplaceAllString(str, "")
|
||||
|
||||
str = strings.ReplaceAll(str, "<", "")
|
||||
str = strings.ReplaceAll(str, ">", "")
|
||||
str = strings.ReplaceAll(str, "\n", "")
|
||||
str = strings.ReplaceAll(str, " ", "")
|
||||
str = strings.ReplaceAll(str, " ", "")
|
||||
|
||||
return str
|
||||
}
|
||||
return ""
|
||||
}
|
||||
40
pkg/strutil/string_internal.go
Normal file
40
pkg/strutil/string_internal.go
Normal file
@ -0,0 +1,40 @@
|
||||
package strutil
|
||||
|
||||
import "strings"
|
||||
|
||||
// splitWordsToLower 将一个字符串按大写字母分割成若干个字符串
|
||||
func splitWordsToLower(s string) []string {
|
||||
var res []string
|
||||
|
||||
upperIndexes := upperIndex(s)
|
||||
l := len(upperIndexes)
|
||||
if upperIndexes == nil || l == 0 {
|
||||
if s != "" {
|
||||
res = append(res, s)
|
||||
}
|
||||
return res
|
||||
}
|
||||
for i := 0; i < l; i++ {
|
||||
if i < l-1 {
|
||||
res = append(res, strings.ToLower(s[upperIndexes[i]:upperIndexes[i+1]]))
|
||||
} else {
|
||||
res = append(res, strings.ToLower(s[upperIndexes[i]:]))
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// upperIndex 获得一个int slice,其元素是一个字符串的所有大写字母索引
|
||||
func upperIndex(s string) []int {
|
||||
var res []int
|
||||
for i := 0; i < len(s); i++ {
|
||||
if 64 < s[i] && s[i] < 91 {
|
||||
res = append(res, i)
|
||||
}
|
||||
}
|
||||
if len(s) > 0 && res != nil && res[0] != 0 {
|
||||
res = append([]int{0}, res...)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
147
pkg/strutil/string_test.go
Normal file
147
pkg/strutil/string_test.go
Normal file
@ -0,0 +1,147 @@
|
||||
package strutil
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestCamelCase(t *testing.T) {
|
||||
require.Equal(t, "fooBar", CamelCase("foo_bar"))
|
||||
require.Equal(t, "fooBar", CamelCase("Foo-Bar"))
|
||||
require.Equal(t, "fooBar", CamelCase("Foo&bar"))
|
||||
require.Equal(t, "fooBar", CamelCase("foo bar"))
|
||||
|
||||
require.NotEqual(t, "FooBar", CamelCase("foo_bar"))
|
||||
}
|
||||
|
||||
func TestCapitalize(t *testing.T) {
|
||||
require.Equal(t, "Foo", Capitalize("foo"))
|
||||
require.Equal(t, "Foo", Capitalize("Foo"))
|
||||
require.Equal(t, "Foo", Capitalize("Foo"))
|
||||
|
||||
require.NotEqual(t, "foo", Capitalize("Foo"))
|
||||
}
|
||||
|
||||
func TestKebabCase(t *testing.T) {
|
||||
require.Equal(t, "foo-bar", KebabCase("Foo Bar-"))
|
||||
require.Equal(t, "foo-bar", KebabCase("foo_Bar"))
|
||||
require.Equal(t, "foo-bar", KebabCase("fooBar"))
|
||||
require.Equal(t, "f-o-o-b-a-r", KebabCase("__FOO_BAR__"))
|
||||
|
||||
require.NotEqual(t, "foo_bar", KebabCase("fooBar"))
|
||||
}
|
||||
|
||||
func TestSnakeCase(t *testing.T) {
|
||||
require.Equal(t, "foo_bar", SnakeCase("Foo Bar-"))
|
||||
require.Equal(t, "foo_bar", SnakeCase("foo_Bar"))
|
||||
require.Equal(t, "foo_bar", SnakeCase("fooBar"))
|
||||
require.Equal(t, "f_o_o_b_a_r", SnakeCase("__FOO_BAR__"))
|
||||
require.Equal(t, "a_bbc_s_a_b_b_c", SnakeCase("aBbc-s$@a&%_B.B^C"))
|
||||
|
||||
require.NotEqual(t, "foo-bar", SnakeCase("foo_Bar"))
|
||||
}
|
||||
|
||||
func TestUpperFirst(t *testing.T) {
|
||||
require.Equal(t, "Foo", UpperFirst("foo"))
|
||||
require.Equal(t, "BAR", UpperFirst("bAR"))
|
||||
require.Equal(t, "FOo", UpperFirst("FOo"))
|
||||
require.Equal(t, "FOo大", UpperFirst("fOo大"))
|
||||
|
||||
require.NotEqual(t, "Bar", UpperFirst("BAR"))
|
||||
}
|
||||
|
||||
func TestLowerFirst(t *testing.T) {
|
||||
require.Equal(t, "foo", LowerFirst("foo"))
|
||||
require.Equal(t, "bAR", LowerFirst("BAR"))
|
||||
require.Equal(t, "fOo", LowerFirst("FOo"))
|
||||
require.Equal(t, "fOo大", LowerFirst("FOo大"))
|
||||
|
||||
require.NotEqual(t, "Bar", LowerFirst("BAR"))
|
||||
}
|
||||
|
||||
func TestPadEnd(t *testing.T) {
|
||||
require.Equal(t, "a", PadEnd("a", 1, "b"))
|
||||
require.Equal(t, "ab", PadEnd("a", 2, "b"))
|
||||
require.Equal(t, "abcdmn", PadEnd("abcd", 6, "mno"))
|
||||
require.Equal(t, "abcdmm", PadEnd("abcd", 6, "m"))
|
||||
require.Equal(t, "abcaba", PadEnd("abc", 6, "ab"))
|
||||
|
||||
require.NotEqual(t, "ba", PadEnd("a", 2, "b"))
|
||||
}
|
||||
|
||||
func TestPadStart(t *testing.T) {
|
||||
require.Equal(t, "a", PadStart("a", 1, "b"))
|
||||
require.Equal(t, "ba", PadStart("a", 2, "b"))
|
||||
require.Equal(t, "mnabcd", PadStart("abcd", 6, "mno"))
|
||||
require.Equal(t, "mmabcd", PadStart("abcd", 6, "m"))
|
||||
require.Equal(t, "abaabc", PadStart("abc", 6, "ab"))
|
||||
|
||||
require.NotEqual(t, "ab", PadStart("a", 2, "b"))
|
||||
}
|
||||
|
||||
func TestBefore(t *testing.T) {
|
||||
require.Equal(t, "lancet", Before("lancet", ""))
|
||||
require.Equal(t, "github.com", Before("github.com/test/lancet", "/"))
|
||||
require.Equal(t, "github.com/", Before("github.com/test/lancet", "test"))
|
||||
}
|
||||
|
||||
func TestBeforeLast(t *testing.T) {
|
||||
require.Equal(t, "lancet", BeforeLast("lancet", ""))
|
||||
require.Equal(t, "github.com/test", BeforeLast("github.com/test/lancet", "/"))
|
||||
require.Equal(t, "github.com/test/", BeforeLast("github.com/test/test/lancet", "test"))
|
||||
|
||||
require.NotEqual(t, "github.com/", BeforeLast("github.com/test/test/lancet", "test"))
|
||||
}
|
||||
|
||||
func TestAfter(t *testing.T) {
|
||||
require.Equal(t, "lancet", After("lancet", ""))
|
||||
require.Equal(t, "test/lancet", After("github.com/test/lancet", "/"))
|
||||
require.Equal(t, "/lancet", After("github.com/test/lancet", "test"))
|
||||
}
|
||||
|
||||
func TestAfterLast(t *testing.T) {
|
||||
require.Equal(t, "lancet", AfterLast("lancet", ""))
|
||||
require.Equal(t, "lancet", AfterLast("github.com/test/lancet", "/"))
|
||||
require.Equal(t, "/lancet", AfterLast("github.com/test/lancet", "test"))
|
||||
require.Equal(t, "/lancet", AfterLast("github.com/test/test/lancet", "test"))
|
||||
|
||||
require.NotEqual(t, "/test/lancet", AfterLast("github.com/test/test/lancet", "test"))
|
||||
}
|
||||
|
||||
func TestIsString(t *testing.T) {
|
||||
require.Equal(t, true, IsString("lancet"))
|
||||
require.Equal(t, true, IsString(""))
|
||||
require.Equal(t, false, IsString(1))
|
||||
require.Equal(t, false, IsString(true))
|
||||
require.Equal(t, false, IsString([]string{}))
|
||||
}
|
||||
|
||||
func TestReverseStr(t *testing.T) {
|
||||
require.Equal(t, "cba", ReverseStr("abc"))
|
||||
require.Equal(t, "54321", ReverseStr("12345"))
|
||||
}
|
||||
|
||||
func TestWrap(t *testing.T) {
|
||||
require.Equal(t, "ab", Wrap("ab", ""))
|
||||
require.Equal(t, "", Wrap("", "*"))
|
||||
require.Equal(t, "*ab*", Wrap("ab", "*"))
|
||||
require.Equal(t, "\"ab\"", Wrap("ab", "\""))
|
||||
require.Equal(t, "'ab'", Wrap("ab", "'"))
|
||||
}
|
||||
|
||||
func TestUnwrap(t *testing.T) {
|
||||
require.Equal(t, "", Unwrap("", "*"))
|
||||
require.Equal(t, "ab", Unwrap("ab", ""))
|
||||
require.Equal(t, "ab", Unwrap("ab", "*"))
|
||||
require.Equal(t, "*ab*", Unwrap("**ab**", "*"))
|
||||
require.Equal(t, "ab", Unwrap("**ab**", "**"))
|
||||
require.Equal(t, "ab", Unwrap("\"ab\"", "\""))
|
||||
require.Equal(t, "*ab", Unwrap("*ab", "*"))
|
||||
require.Equal(t, "ab*", Unwrap("ab*", "*"))
|
||||
require.Equal(t, "*", Unwrap("***", "*"))
|
||||
|
||||
require.Equal(t, "", Unwrap("**", "*"))
|
||||
require.Equal(t, "***", Unwrap("***", "**"))
|
||||
require.Equal(t, "**", Unwrap("**", "**"))
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user