182 lines
4.2 KiB
Go
182 lines
4.2 KiB
Go
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
|
||
}
|