Files
36Wisdom/common/pinyin.go
T
2026-08-14 16:11:10 +08:00

108 lines
2.7 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 common
import (
"encoding/json"
"sort"
"strings"
"unicode"
"github.com/mozillazg/go-pinyin"
"36wisdom/biz/consts"
)
// AnnotatePinyin 写时一次性标注:词表最长匹配优先(整体转拼音),未命中逐字转
// pinyin.Tone 带声调);返回逐字对齐的 JSON 数组字符串,非汉字对应空串,
// 下标与原文 rune 一一对应。纯函数,文本未变结果不变(幂等)。
func AnnotatePinyin(text string) string {
runes := []rune(text)
out := make([]string, len(runes))
if len(runes) == 0 {
return "[]"
}
words := make([]string, 0, len(consts.PinyinOverrides))
for w := range consts.PinyinOverrides {
words = append(words, w)
}
sort.Slice(words, func(i, j int) bool { return len(words[i]) > len(words[j]) })
// 词表最长匹配切分:命中片段整体标注(词表拼音音节数须与字数一致)
for i := 0; i < len(runes); {
matched := false
for _, w := range words {
n := len([]rune(w))
if i+n > len(runes) || string(runes[i:i+n]) != w {
continue
}
pys := strings.Fields(consts.PinyinOverrides[w])
if len(pys) != n {
continue
}
copy(out[i:i+n], pys)
i += n
matched = true
break
}
if !matched {
i++
}
}
// 未命中汉字逐字转拼音:词典缺失字(生僻字等)SinglePinyin 返回空串,
// 该字自然保持 "",后续字不错位
args := pinyin.Args{Style: pinyin.Tone}
i := 0
for _, r := range text {
if out[i] == "" && unicode.Is(unicode.Han, r) {
if pys := pinyin.SinglePinyin(r, args); len(pys) > 0 {
out[i] = pys[0]
}
}
i++
}
b, _ := json.Marshal(out)
return string(b)
}
// ToPinyinPlain 文本 → 空格分隔带声调拼音串(词表最长匹配优先,未命中逐字转),
// 与种子数据 strategy.pinyin 格式一致;用于写时标注 name → pinyin。
func ToPinyinPlain(text string) string {
runes := []rune(text)
if len(runes) == 0 {
return ""
}
words := make([]string, 0, len(consts.PinyinOverrides))
for w := range consts.PinyinOverrides {
words = append(words, w)
}
sort.Slice(words, func(i, j int) bool { return len(words[i]) > len(words[j]) })
parts := make([]string, 0, len(runes))
args := pinyin.Args{Style: pinyin.Tone}
for i := 0; i < len(runes); {
matched := false
for _, w := range words {
n := len([]rune(w))
if i+n > len(runes) || string(runes[i:i+n]) != w {
continue
}
parts = append(parts, strings.Fields(consts.PinyinOverrides[w])...)
i += n
matched = true
break
}
if matched {
continue
}
if unicode.Is(unicode.Han, runes[i]) {
if pys := pinyin.SinglePinyin(runes[i], args); len(pys) > 0 {
parts = append(parts, pys[0])
}
}
i++
}
return strings.Join(parts, " ")
}