Files
monibuca/pkg/util/rune_conv.go
2025-01-15 15:09:39 +08:00

111 lines
2.7 KiB
Go
Executable File

package util
import (
"encoding/base64"
"strings"
"unicode"
"github.com/mozillazg/go-pinyin"
)
// StringSegment 表示字符串片段及其类型
type StringSegment struct {
Text string
StrType int // 0: 英文/数字, 1: 中文, 2: 其他语言
}
// SplitRuneString 将字符串切割成不同类型的片段
func SplitRuneString(s string) []StringSegment {
var segments []StringSegment
var builder strings.Builder
var currentType int // 当前正在构建的片段类型
// 获取字符类型
getCharType := func(r rune) int {
switch {
case unicode.Is(unicode.Han, r):
return 1 // 中文
case unicode.Is(unicode.Hiragana, r) || unicode.Is(unicode.Katakana, r):
return 2 // 日语假名
case unicode.Is(unicode.Hangul, r):
return 2 // 韩语
case unicode.Is(unicode.Thai, r):
return 2 // 泰语
case unicode.IsLetter(r) || unicode.IsDigit(r):
return 0 // 英文或数字
default:
// 其他 Unicode 字符,如果不是空格或标点,也认为是其他语言
if !unicode.IsSpace(r) && !unicode.IsPunct(r) {
return 2
}
// 对于空格和标点,跟随当前类型
return currentType
}
}
// 添加当前片段到结果中
addSegment := func() {
if builder.Len() > 0 {
segments = append(segments, StringSegment{
Text: builder.String(),
StrType: currentType,
})
builder.Reset()
}
}
runes := []rune(s)
if len(runes) == 0 {
return segments
}
// 初始化第一个字符
firstChar := runes[0]
currentType = getCharType(firstChar)
builder.WriteRune(firstChar)
// 处理剩余字符
for i := 1; i < len(runes); i++ {
currentChar := runes[i]
charType := getCharType(currentChar)
// 如果字符类型发生变化,添加新片段
if charType != currentType {
addSegment()
currentType = charType
}
builder.WriteRune(currentChar)
}
// 添加最后一个片段
addSegment()
return segments
}
// ConvertRuneToEn 将字符串中的中文转换为拼音,其他语言转换为 base64
func ConvertRuneToEn(s string) string {
segments := SplitRuneString(s)
var result strings.Builder
a := pinyin.NewArgs()
for i, seg := range segments {
switch seg.StrType {
case 0: // 英文/数字
result.WriteString(seg.Text)
case 1: // 中文
pinyinSlice := pinyin.LazyPinyin(seg.Text, a)
result.WriteString(strings.Join(pinyinSlice, ""))
case 2: // 其他语言,使用 base64 编码(不带填充)
result.WriteString(base64.RawURLEncoding.EncodeToString([]byte(seg.Text)))
}
// 如果不是最后一个片段,且下一个片段类型不同,添加空格
if i < len(segments)-1 && segments[i+1].StrType != seg.StrType {
result.WriteString("")
}
}
return result.String()
}