Files
mayfly-go/server/pkg/utils/stringx/stringx.go

178 lines
4.3 KiB
Go
Raw Normal View History

package stringx
2020-09-01 10:34:11 +08:00
import (
"bytes"
"strings"
"text/template"
2026-04-15 12:47:10 +08:00
"unicode"
2024-12-08 13:04:23 +08:00
"unicode/utf8"
2020-09-01 10:34:11 +08:00
)
// 可判断中文
func Len(str string) int {
2020-09-01 10:34:11 +08:00
return len([]rune(str))
}
// 去除字符串左右空字符
func Trim(str string) string {
2020-09-01 10:34:11 +08:00
return strings.Trim(str, " ")
}
// 去除字符串左右空字符与\n\r换行回车符
func TrimSpaceAndBr(str string) string {
2022-11-02 19:27:40 +08:00
return strings.TrimFunc(str, func(r rune) bool {
s := string(r)
return s == " " || s == "\n" || s == "\r"
2022-11-02 19:27:40 +08:00
})
}
2020-09-01 10:34:11 +08:00
func SubString(str string, begin, end int) (substr string) {
// 将字符串的转换成[]rune
rs := []rune(str)
lth := len(rs)
// 简单的越界判断
if begin < 0 {
begin = 0
}
if begin >= lth {
begin = lth
}
if end > lth {
end = lth
}
// 返回子串
return string(rs[begin:end])
}
2026-04-15 12:47:10 +08:00
// Camel2Snake 将驼峰命名转换为下划线命名
// 例如: "userName" -> "user_name", "HTTPServer" -> "http_server"
func Camel2Snake(name string) string {
2021-01-08 15:37:32 +08:00
if name == "" {
return ""
}
2026-04-15 12:47:10 +08:00
var result strings.Builder
for i, r := range name {
// 如果当前字符是大写字母
if unicode.IsUpper(r) {
// 如果不是第一个字符,且前一个字符不是下划线,则添加下划线
if i > 0 {
result.WriteRune('_')
2021-01-08 15:37:32 +08:00
}
2026-04-15 12:47:10 +08:00
// 转换为小写
result.WriteRune(unicode.ToLower(r))
} else {
result.WriteRune(r)
2021-01-08 15:37:32 +08:00
}
}
2026-04-15 12:47:10 +08:00
return result.String()
2021-01-08 15:37:32 +08:00
}
2020-09-01 10:34:11 +08:00
func UnicodeIndex(str, substr string) int {
// 子串在字符串的字节位置
result := strings.Index(str, substr)
if result >= 0 {
// 获得子串之前的字符串并转换成[]byte
prefix := []byte(str)[0:result]
// 将子串之前的字符串转换成[]rune
rs := []rune(string(prefix))
// 获得子串之前的字符串的长度,便是子串在字符串的字符位置
result = len(rs)
}
return result
}
// 字符串模板解析
2025-03-11 12:42:20 +08:00
func TemplateResolve(temp string, data any) (string, error) {
t, err := template.New("string-temp").Parse(temp)
if err != nil {
return "", err
}
2020-09-01 10:34:11 +08:00
var tmplBytes bytes.Buffer
2025-03-11 12:42:20 +08:00
err = t.Execute(&tmplBytes, data)
2020-09-01 10:34:11 +08:00
if err != nil {
2025-03-11 12:42:20 +08:00
return "", err
2020-09-01 10:34:11 +08:00
}
2025-03-11 12:42:20 +08:00
return tmplBytes.String(), nil
2020-09-01 10:34:11 +08:00
}
func ReverStrTemplate(temp, str string, res map[string]any) {
2020-09-01 10:34:11 +08:00
index := UnicodeIndex(temp, "{")
ei := UnicodeIndex(temp, "}") + 1
next := Trim(temp[ei:])
2020-09-01 10:34:11 +08:00
nextContain := UnicodeIndex(next, "{")
nextIndexValue := next
if nextContain != -1 {
nextIndexValue = SubString(next, 0, nextContain)
}
key := temp[index+1 : ei-1]
// 如果后面没有内容了,则取字符串的长度即可
var valueLastIndex int
if nextIndexValue == "" {
valueLastIndex = Len(str)
2020-09-01 10:34:11 +08:00
} else {
valueLastIndex = UnicodeIndex(str, nextIndexValue)
}
value := Trim(SubString(str, index, valueLastIndex))
2020-09-01 10:34:11 +08:00
res[key] = value
// 如果后面的还有需要解析的,则递归调用解析
if nextContain != -1 {
ReverStrTemplate(next, Trim(SubString(str, UnicodeIndex(str, value)+Len(value), Len(str))), res)
2020-09-01 10:34:11 +08:00
}
}
2026-04-15 12:47:10 +08:00
// Truncate 截断字符串并在中间部分显示指定的替换字符串。
// 该函数基于 Unicode 字符rune进行计算支持中文等多字节字符。
//
// 参数说明:
// - s: 原始字符串
// - length: 截断后字符串的总最大长度(包含前缀、替换串和后缀)。
// 如果原字符串长度小于等于 length则直接返回原字符串。
// - prefixLen: 保留的前缀字符数量。
// - replace: 用于替换中间被截断部分的字符串(如 "...")。
//
// 返回:
// - 格式化后的字符串。
//
// 示例:
//
// Truncate("Hello, World!", 10, 5, "...") -> "Hello...ld!"
// Truncate("你好世界", 3, 1, "..") -> "你..界"
2024-12-08 13:04:23 +08:00
func Truncate(s string, length int, prefixLen int, replace string) string {
totalRunes := utf8.RuneCountInString(s)
// 如果字符串长度小于或等于指定的 length直接返回原字符串
if totalRunes <= length {
return s
}
2024-12-08 13:04:23 +08:00
// 如果字符串长度小于或等于 prefixLen直接返回原字符串
if totalRunes <= prefixLen {
return s
}
2024-12-08 13:04:23 +08:00
// 计算 suffixLen
suffixLen := length - prefixLen
// 确保 suffixLen 不会越界
if suffixLen <= 0 {
runes := []rune(s)
return string(runes[:length]) + replace
}
// 获取前 prefixLen 个字符
runes := []rune(s)
prefix := string(runes[:prefixLen])
// 获取后 suffixLen 个字符
suffix := string(runes[len(runes)-suffixLen:])
// 返回格式化后的字符串
return prefix + replace + suffix
}