Files
web_hgtv_server/pub/common/utils/strings.go
T
2026-10-24 11:22:21 +08:00

182 lines
4.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package utils
import (
"encoding/json"
"math/rand/v2"
"strings"
"videoweb/pub/common/netutil"
"github.com/gosimple/slug"
)
// BinarySearch BinarySearch
func BinarySearch(s []string, t string, n int) (idx int) {
idx = -1
if n == 0 {
return
}
start, end := 0, n-1
for start <= end {
mid := (start + end) >> 1
if s[mid] < t {
start = mid + 1
} else if s[mid] > t {
end = mid - 1
} else {
idx = mid
break
}
}
return
}
var YesOrNo = map[bool]string{
true: "是",
false: "否",
}
// ApplyImgCdn 尝试解析节点 Content JSON,若含 "img" 字段则对其拼接 CDN 后重新序列化。
// 不符合 {"img": "..."} 结构的 Content 原样返回。
func ApplyImgCdn(cdn, content string) string {
if content == "" || cdn == "" {
return content
}
var m map[string]interface{}
if err := json.Unmarshal([]byte(content), &m); err != nil {
return content // 非 JSON 对象,原样返回
}
imgVal, ok := m["img"]
if !ok {
return content // 无 img 字段,原样返回
}
imgStr, ok := imgVal.(string)
if !ok || imgStr == "" {
return content
}
m["img"] = netutil.MergeURL(cdn, imgStr)
b, err := json.Marshal(m)
if err != nil {
return content
}
return string(b)
}
// 截取指定长度的字符串
func GetPrefix(s string, n int) string {
runes := []rune(s)
if len(runes) <= n {
return s
}
return string(runes[:n])
}
func GetRandomLetters(n int) string {
const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
b := make([]byte, n)
for i := range b {
b[i] = letters[rand.IntN(len(letters))]
}
return string(b)
}
func GetSlugInfo(text string) string {
return SanitizeSlug(slug.Make(text))
}
// SanitizeSlug 去掉 slug 中的横杠等特殊符号,只保留字母和数字
func SanitizeSlug(s string) string {
s = strings.TrimSpace(s)
if s == "" {
return ""
}
var b strings.Builder
b.Grow(len(s))
for _, r := range s {
if r >= 'a' && r <= 'z' || r >= 'A' && r <= 'Z' || r >= '0' && r <= '9' {
b.WriteRune(r)
}
}
return b.String()
}
// IsSlugAllDigits 判断 slug 是否全为数字
func IsSlugAllDigits(s string) bool {
s = strings.TrimSpace(s)
if s == "" {
return false
}
for _, r := range s {
if r < '0' || r > '9' {
return false
}
}
return true
}
// RandomSlugLength 随机 slug 长度
const RandomSlugLength = 8
// MakeRandomSlug 生成唯一的随机 slug(8 位小写字母);exists 返回 true 表示已被占用。
func MakeRandomSlug(exists func(string) bool) string {
for {
s := strings.ToLower(GetRandomLetters(RandomSlugLength))
if !exists(s) {
return s
}
}
}
// GetSlugAbbr 取标题的拼音首字母缩写(中文每字取首字母,英文每词取首字母),全小写。
func GetSlugAbbr(text string) string {
s := strings.ToLower(slug.Make(text))
var b strings.Builder
newWord := true
for _, r := range s {
if r == '-' || r == '_' {
newWord = true
continue
}
if newWord && ((r >= 'a' && r <= 'z') || (r >= '0' && r <= '9')) {
b.WriteRune(r)
newWord = false
}
}
return b.String()
}
// AbbrSlugMaxLen slug 最大长度(含碰撞时追加的随机后缀)。
const AbbrSlugMaxLen = 20
// MakeAbbrSlug 优先按标题拼音首字母缩写生成 slug;缩写为空或全数字时回退 5 位随机字母,碰撞时追加 3 位随机字母,整体长度不超过 AbbrSlugMaxLen。
func MakeAbbrSlug(source string, exists func(string) bool) string {
abbr := GetSlugAbbr(source)
if abbr == "" || IsSlugAllDigits(abbr) {
abbr = strings.ToLower(GetRandomLetters(5))
}
const suffixLen = 3
baseMax := AbbrSlugMaxLen - suffixLen
if len(abbr) > baseMax {
abbr = abbr[:baseMax]
}
final := abbr
for exists(final) {
final = abbr + strings.ToLower(GetRandomLetters(suffixLen))
}
return final
}
// MakeUniqueSlug 生成唯一 slug;exists 返回 true 表示已被占用。生成结果不能全是数字。
func MakeUniqueSlug(source string, exists func(string) bool) string {
pinyin := GetSlugInfo(source)
if pinyin == "" {
pinyin = GetRandomLetters(5)
} else if IsSlugAllDigits(pinyin) {
pinyin = pinyin + GetRandomLetters(3)
}
finalSlug := pinyin
for exists(finalSlug) {
finalSlug = pinyin + GetRandomLetters(3)
}
return finalSlug
}