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, " ") }