[{"data":1,"prerenderedAt":878},["ShallowReactive",2],{"article-go-pinyin-to-han":3},{"id":4,"title":5,"body":6,"date":867,"description":42,"extension":868,"meta":869,"navigation":59,"path":873,"rawbody":874,"seo":875,"stem":876,"__hash__":877},"content\u002Fyehangzhou\u002Fposts\u002Fgo-pinyin-to-han.md","Go语言实现拼音转化为汉字",{"type":7,"value":8,"toc":865},"minimark",[9,13,16,24,27,30,33,36,746,749,752,846,849,858,861],[10,11,12],"p",{},"预先说明：以项目名为 x 作为示例",[10,14,15],{},"第一步：在GitHub找个汉字拼音字典（随便找了一个输入法项目的字典）",[10,17,18],{},[19,20,21],"a",{"href":21,"rel":22},"https:\u002F\u002Fgithub.com\u002FMobtgZhang\u002FLingJian-Pinyin\u002Fblob\u002Fmain\u002Fdata\u002Fpinyin_dict.txt",[23],"nofollow",[10,25,26],{},"第二步：把字典下载下来放在项目里，例如：data\u002Fpinyin_dict.txt",[10,28,29],{},"x\u002Fdata\u002Fpinyin_dict.txt",[10,31,32],{},"第三步：创建 com\u002Fpinyin_han.go 文件，把代码复制进去",[10,34,35],{},"x\u002Fcom\u002Fpinyin_han.go",[37,38,43],"pre",{"className":39,"code":40,"language":41,"meta":42,"style":42},"language-go shiki shiki-themes github-light github-dark","package com\n\nimport (\n    \"bufio\"\n    \"os\"\n    \"strings\"\n    \"sync\"\n)\n\ntype PinyinHan struct {\n    pyToHan     map[string][]string\n    abbrToHan   map[string][]string \u002F\u002F 简拼映射\n    noToneToHan map[string][]string \u002F\u002F 无声调映射\n    mutex       sync.RWMutex\n}\n\nfunc NewPinyinHan() *PinyinHan {\n    return &PinyinHan{\n        pyToHan:     make(map[string][]string),\n        abbrToHan:   make(map[string][]string),\n        noToneToHan: make(map[string][]string),\n    }\n}\n\nfunc (p *PinyinHan) LoadDictionary(filename string) error {\n    p.mutex.Lock()\n    defer p.mutex.Unlock()\n\n    file, err := os.Open(filename)\n    if err != nil {\n        return err\n    }\n    defer func(file *os.File) {\n        _ = file.Close()\n    }(file)\n\n    scanner := bufio.NewScanner(file)\n    for scanner.Scan() {\n        line := strings.TrimSpace(scanner.Text())\n        if line == \"\" {\n            continue\n        }\n\n        parts := strings.Fields(line)\n        if len(parts) >= 2 {\n            pinyin := parts[0]\n            hanzi := parts[1]\n\n            \u002F\u002F 标准拼音映射\n            p.pyToHan[pinyin] = append(p.pyToHan[pinyin], hanzi)\n\n            \u002F\u002F 构建简拼映射\n            abbr := p.getAbbreviation(pinyin)\n            p.abbrToHan[abbr] = append(p.abbrToHan[abbr], hanzi)\n\n            \u002F\u002F 构建无声调映射\n            noTone := p.removeTone(pinyin)\n            p.noToneToHan[noTone] = append(p.noToneToHan[noTone], hanzi)\n        }\n    }\n\n    return scanner.Err()\n}\n\nfunc (p *PinyinHan) getAbbreviation(pinyin string) string {\n    syllables := strings.Fields(pinyin)\n    var abbr strings.Builder\n    for _, syl := range syllables {\n        if len(syl) > 0 {\n            abbr.WriteByte(syl[0])\n        }\n    }\n    return abbr.String()\n}\n\nfunc (p *PinyinHan) removeTone(pinyin string) string {\n    \u002F\u002F 简单的声调数字去除\n    result := make([]byte, 0, len(pinyin))\n    for i := 0; i \u003C len(pinyin); i++ {\n        if pinyin[i] \u003C '1' || pinyin[i] > '4' {\n            result = append(result, pinyin[i])\n        }\n    }\n    return string(result)\n}\n\nfunc (p *PinyinHan) Convert(pinyin string) []string {\n    p.mutex.RLock()\n    defer p.mutex.RUnlock()\n\n    \u002F\u002F 优先级：精确匹配 > 无声调匹配 > 简拼匹配\n    if result, exists := p.pyToHan[pinyin]; exists {\n        return result\n    }\n\n    noTone := p.removeTone(pinyin)\n    if result, exists := p.noToneToHan[noTone]; exists {\n        return result\n    }\n\n    if result, exists := p.abbrToHan[pinyin]; exists {\n        return result\n    }\n\n    return nil\n}\n\nfunc (p *PinyinHan) Run(dictPath string, pinyin []string) ([]string, error) {\n    err := p.LoadDictionary(dictPath)\n    if err != nil {\n        return nil, err\n    }\n\n    var out = make([]string, 0)\n    for _, v := range pinyin {\n        v = strings.ReplaceAll(v, \" \", \"\")\n        result := p.Convert(v)\n        for _, s := range result {\n            out = append(out, s)\n        }\n    }\n    return out, nil\n}\n","go","",[44,45,46,54,61,67,73,79,85,91,97,102,108,114,120,126,132,138,143,149,155,161,167,173,179,184,189,195,201,207,212,218,224,230,235,241,247,253,258,264,270,276,282,288,294,299,305,311,317,323,328,334,340,345,351,357,363,368,374,380,386,391,396,401,407,412,417,423,429,435,441,447,453,458,463,469,474,479,485,491,497,503,509,515,520,525,531,536,541,547,553,559,564,570,576,582,587,592,598,604,609,614,619,625,630,635,640,646,651,656,662,668,673,679,684,689,695,701,707,713,719,725,730,735,741],"code",{"__ignoreMap":42},[47,48,51],"span",{"class":49,"line":50},"line",1,[47,52,53],{},"package com\n",[47,55,57],{"class":49,"line":56},2,[47,58,60],{"emptyLinePlaceholder":59},true,"\n",[47,62,64],{"class":49,"line":63},3,[47,65,66],{},"import (\n",[47,68,70],{"class":49,"line":69},4,[47,71,72],{},"    \"bufio\"\n",[47,74,76],{"class":49,"line":75},5,[47,77,78],{},"    \"os\"\n",[47,80,82],{"class":49,"line":81},6,[47,83,84],{},"    \"strings\"\n",[47,86,88],{"class":49,"line":87},7,[47,89,90],{},"    \"sync\"\n",[47,92,94],{"class":49,"line":93},8,[47,95,96],{},")\n",[47,98,100],{"class":49,"line":99},9,[47,101,60],{"emptyLinePlaceholder":59},[47,103,105],{"class":49,"line":104},10,[47,106,107],{},"type PinyinHan struct {\n",[47,109,111],{"class":49,"line":110},11,[47,112,113],{},"    pyToHan     map[string][]string\n",[47,115,117],{"class":49,"line":116},12,[47,118,119],{},"    abbrToHan   map[string][]string \u002F\u002F 简拼映射\n",[47,121,123],{"class":49,"line":122},13,[47,124,125],{},"    noToneToHan map[string][]string \u002F\u002F 无声调映射\n",[47,127,129],{"class":49,"line":128},14,[47,130,131],{},"    mutex       sync.RWMutex\n",[47,133,135],{"class":49,"line":134},15,[47,136,137],{},"}\n",[47,139,141],{"class":49,"line":140},16,[47,142,60],{"emptyLinePlaceholder":59},[47,144,146],{"class":49,"line":145},17,[47,147,148],{},"func NewPinyinHan() *PinyinHan {\n",[47,150,152],{"class":49,"line":151},18,[47,153,154],{},"    return &PinyinHan{\n",[47,156,158],{"class":49,"line":157},19,[47,159,160],{},"        pyToHan:     make(map[string][]string),\n",[47,162,164],{"class":49,"line":163},20,[47,165,166],{},"        abbrToHan:   make(map[string][]string),\n",[47,168,170],{"class":49,"line":169},21,[47,171,172],{},"        noToneToHan: make(map[string][]string),\n",[47,174,176],{"class":49,"line":175},22,[47,177,178],{},"    }\n",[47,180,182],{"class":49,"line":181},23,[47,183,137],{},[47,185,187],{"class":49,"line":186},24,[47,188,60],{"emptyLinePlaceholder":59},[47,190,192],{"class":49,"line":191},25,[47,193,194],{},"func (p *PinyinHan) LoadDictionary(filename string) error {\n",[47,196,198],{"class":49,"line":197},26,[47,199,200],{},"    p.mutex.Lock()\n",[47,202,204],{"class":49,"line":203},27,[47,205,206],{},"    defer p.mutex.Unlock()\n",[47,208,210],{"class":49,"line":209},28,[47,211,60],{"emptyLinePlaceholder":59},[47,213,215],{"class":49,"line":214},29,[47,216,217],{},"    file, err := os.Open(filename)\n",[47,219,221],{"class":49,"line":220},30,[47,222,223],{},"    if err != nil {\n",[47,225,227],{"class":49,"line":226},31,[47,228,229],{},"        return err\n",[47,231,233],{"class":49,"line":232},32,[47,234,178],{},[47,236,238],{"class":49,"line":237},33,[47,239,240],{},"    defer func(file *os.File) {\n",[47,242,244],{"class":49,"line":243},34,[47,245,246],{},"        _ = file.Close()\n",[47,248,250],{"class":49,"line":249},35,[47,251,252],{},"    }(file)\n",[47,254,256],{"class":49,"line":255},36,[47,257,60],{"emptyLinePlaceholder":59},[47,259,261],{"class":49,"line":260},37,[47,262,263],{},"    scanner := bufio.NewScanner(file)\n",[47,265,267],{"class":49,"line":266},38,[47,268,269],{},"    for scanner.Scan() {\n",[47,271,273],{"class":49,"line":272},39,[47,274,275],{},"        line := strings.TrimSpace(scanner.Text())\n",[47,277,279],{"class":49,"line":278},40,[47,280,281],{},"        if line == \"\" {\n",[47,283,285],{"class":49,"line":284},41,[47,286,287],{},"            continue\n",[47,289,291],{"class":49,"line":290},42,[47,292,293],{},"        }\n",[47,295,297],{"class":49,"line":296},43,[47,298,60],{"emptyLinePlaceholder":59},[47,300,302],{"class":49,"line":301},44,[47,303,304],{},"        parts := strings.Fields(line)\n",[47,306,308],{"class":49,"line":307},45,[47,309,310],{},"        if len(parts) >= 2 {\n",[47,312,314],{"class":49,"line":313},46,[47,315,316],{},"            pinyin := parts[0]\n",[47,318,320],{"class":49,"line":319},47,[47,321,322],{},"            hanzi := parts[1]\n",[47,324,326],{"class":49,"line":325},48,[47,327,60],{"emptyLinePlaceholder":59},[47,329,331],{"class":49,"line":330},49,[47,332,333],{},"            \u002F\u002F 标准拼音映射\n",[47,335,337],{"class":49,"line":336},50,[47,338,339],{},"            p.pyToHan[pinyin] = append(p.pyToHan[pinyin], hanzi)\n",[47,341,343],{"class":49,"line":342},51,[47,344,60],{"emptyLinePlaceholder":59},[47,346,348],{"class":49,"line":347},52,[47,349,350],{},"            \u002F\u002F 构建简拼映射\n",[47,352,354],{"class":49,"line":353},53,[47,355,356],{},"            abbr := p.getAbbreviation(pinyin)\n",[47,358,360],{"class":49,"line":359},54,[47,361,362],{},"            p.abbrToHan[abbr] = append(p.abbrToHan[abbr], hanzi)\n",[47,364,366],{"class":49,"line":365},55,[47,367,60],{"emptyLinePlaceholder":59},[47,369,371],{"class":49,"line":370},56,[47,372,373],{},"            \u002F\u002F 构建无声调映射\n",[47,375,377],{"class":49,"line":376},57,[47,378,379],{},"            noTone := p.removeTone(pinyin)\n",[47,381,383],{"class":49,"line":382},58,[47,384,385],{},"            p.noToneToHan[noTone] = append(p.noToneToHan[noTone], hanzi)\n",[47,387,389],{"class":49,"line":388},59,[47,390,293],{},[47,392,394],{"class":49,"line":393},60,[47,395,178],{},[47,397,399],{"class":49,"line":398},61,[47,400,60],{"emptyLinePlaceholder":59},[47,402,404],{"class":49,"line":403},62,[47,405,406],{},"    return scanner.Err()\n",[47,408,410],{"class":49,"line":409},63,[47,411,137],{},[47,413,415],{"class":49,"line":414},64,[47,416,60],{"emptyLinePlaceholder":59},[47,418,420],{"class":49,"line":419},65,[47,421,422],{},"func (p *PinyinHan) getAbbreviation(pinyin string) string {\n",[47,424,426],{"class":49,"line":425},66,[47,427,428],{},"    syllables := strings.Fields(pinyin)\n",[47,430,432],{"class":49,"line":431},67,[47,433,434],{},"    var abbr strings.Builder\n",[47,436,438],{"class":49,"line":437},68,[47,439,440],{},"    for _, syl := range syllables {\n",[47,442,444],{"class":49,"line":443},69,[47,445,446],{},"        if len(syl) > 0 {\n",[47,448,450],{"class":49,"line":449},70,[47,451,452],{},"            abbr.WriteByte(syl[0])\n",[47,454,456],{"class":49,"line":455},71,[47,457,293],{},[47,459,461],{"class":49,"line":460},72,[47,462,178],{},[47,464,466],{"class":49,"line":465},73,[47,467,468],{},"    return abbr.String()\n",[47,470,472],{"class":49,"line":471},74,[47,473,137],{},[47,475,477],{"class":49,"line":476},75,[47,478,60],{"emptyLinePlaceholder":59},[47,480,482],{"class":49,"line":481},76,[47,483,484],{},"func (p *PinyinHan) removeTone(pinyin string) string {\n",[47,486,488],{"class":49,"line":487},77,[47,489,490],{},"    \u002F\u002F 简单的声调数字去除\n",[47,492,494],{"class":49,"line":493},78,[47,495,496],{},"    result := make([]byte, 0, len(pinyin))\n",[47,498,500],{"class":49,"line":499},79,[47,501,502],{},"    for i := 0; i \u003C len(pinyin); i++ {\n",[47,504,506],{"class":49,"line":505},80,[47,507,508],{},"        if pinyin[i] \u003C '1' || pinyin[i] > '4' {\n",[47,510,512],{"class":49,"line":511},81,[47,513,514],{},"            result = append(result, pinyin[i])\n",[47,516,518],{"class":49,"line":517},82,[47,519,293],{},[47,521,523],{"class":49,"line":522},83,[47,524,178],{},[47,526,528],{"class":49,"line":527},84,[47,529,530],{},"    return string(result)\n",[47,532,534],{"class":49,"line":533},85,[47,535,137],{},[47,537,539],{"class":49,"line":538},86,[47,540,60],{"emptyLinePlaceholder":59},[47,542,544],{"class":49,"line":543},87,[47,545,546],{},"func (p *PinyinHan) Convert(pinyin string) []string {\n",[47,548,550],{"class":49,"line":549},88,[47,551,552],{},"    p.mutex.RLock()\n",[47,554,556],{"class":49,"line":555},89,[47,557,558],{},"    defer p.mutex.RUnlock()\n",[47,560,562],{"class":49,"line":561},90,[47,563,60],{"emptyLinePlaceholder":59},[47,565,567],{"class":49,"line":566},91,[47,568,569],{},"    \u002F\u002F 优先级：精确匹配 > 无声调匹配 > 简拼匹配\n",[47,571,573],{"class":49,"line":572},92,[47,574,575],{},"    if result, exists := p.pyToHan[pinyin]; exists {\n",[47,577,579],{"class":49,"line":578},93,[47,580,581],{},"        return result\n",[47,583,585],{"class":49,"line":584},94,[47,586,178],{},[47,588,590],{"class":49,"line":589},95,[47,591,60],{"emptyLinePlaceholder":59},[47,593,595],{"class":49,"line":594},96,[47,596,597],{},"    noTone := p.removeTone(pinyin)\n",[47,599,601],{"class":49,"line":600},97,[47,602,603],{},"    if result, exists := p.noToneToHan[noTone]; exists {\n",[47,605,607],{"class":49,"line":606},98,[47,608,581],{},[47,610,612],{"class":49,"line":611},99,[47,613,178],{},[47,615,617],{"class":49,"line":616},100,[47,618,60],{"emptyLinePlaceholder":59},[47,620,622],{"class":49,"line":621},101,[47,623,624],{},"    if result, exists := p.abbrToHan[pinyin]; exists {\n",[47,626,628],{"class":49,"line":627},102,[47,629,581],{},[47,631,633],{"class":49,"line":632},103,[47,634,178],{},[47,636,638],{"class":49,"line":637},104,[47,639,60],{"emptyLinePlaceholder":59},[47,641,643],{"class":49,"line":642},105,[47,644,645],{},"    return nil\n",[47,647,649],{"class":49,"line":648},106,[47,650,137],{},[47,652,654],{"class":49,"line":653},107,[47,655,60],{"emptyLinePlaceholder":59},[47,657,659],{"class":49,"line":658},108,[47,660,661],{},"func (p *PinyinHan) Run(dictPath string, pinyin []string) ([]string, error) {\n",[47,663,665],{"class":49,"line":664},109,[47,666,667],{},"    err := p.LoadDictionary(dictPath)\n",[47,669,671],{"class":49,"line":670},110,[47,672,223],{},[47,674,676],{"class":49,"line":675},111,[47,677,678],{},"        return nil, err\n",[47,680,682],{"class":49,"line":681},112,[47,683,178],{},[47,685,687],{"class":49,"line":686},113,[47,688,60],{"emptyLinePlaceholder":59},[47,690,692],{"class":49,"line":691},114,[47,693,694],{},"    var out = make([]string, 0)\n",[47,696,698],{"class":49,"line":697},115,[47,699,700],{},"    for _, v := range pinyin {\n",[47,702,704],{"class":49,"line":703},116,[47,705,706],{},"        v = strings.ReplaceAll(v, \" \", \"\")\n",[47,708,710],{"class":49,"line":709},117,[47,711,712],{},"        result := p.Convert(v)\n",[47,714,716],{"class":49,"line":715},118,[47,717,718],{},"        for _, s := range result {\n",[47,720,722],{"class":49,"line":721},119,[47,723,724],{},"            out = append(out, s)\n",[47,726,728],{"class":49,"line":727},120,[47,729,293],{},[47,731,733],{"class":49,"line":732},121,[47,734,178],{},[47,736,738],{"class":49,"line":737},122,[47,739,740],{},"    return out, nil\n",[47,742,744],{"class":49,"line":743},123,[47,745,137],{},[10,747,748],{},"第四步：直接调用（以Test为例）",[10,750,751],{},"x\u002Ftest\u002Fpinyin_han_test.go",[37,753,755],{"className":39,"code":754,"language":41,"meta":42,"style":42},"package test\n\nimport (\n    \"testing\"\n    \"x\u002Fcom\"\n)\n\nfunc TestPinyinHan(t *testing.T) {\n\n    var pinyin = []string{\"guangdong\", \"hainan\", \"fujian\", \"taiwan\", \"a\"}\n\n    han, err := com.NewPinyinHan().Run(\"..\u002Fdata\u002Fpinyin_dict.txt\", pinyin)\n\n    if err != nil {\n        t.Error(err)\n        return\n    }\n\n    t.Log(han)\n}\n",[44,756,757,762,766,770,775,780,784,788,793,797,802,806,811,815,819,824,829,833,837,842],{"__ignoreMap":42},[47,758,759],{"class":49,"line":50},[47,760,761],{},"package test\n",[47,763,764],{"class":49,"line":56},[47,765,60],{"emptyLinePlaceholder":59},[47,767,768],{"class":49,"line":63},[47,769,66],{},[47,771,772],{"class":49,"line":69},[47,773,774],{},"    \"testing\"\n",[47,776,777],{"class":49,"line":75},[47,778,779],{},"    \"x\u002Fcom\"\n",[47,781,782],{"class":49,"line":81},[47,783,96],{},[47,785,786],{"class":49,"line":87},[47,787,60],{"emptyLinePlaceholder":59},[47,789,790],{"class":49,"line":93},[47,791,792],{},"func TestPinyinHan(t *testing.T) {\n",[47,794,795],{"class":49,"line":99},[47,796,60],{"emptyLinePlaceholder":59},[47,798,799],{"class":49,"line":104},[47,800,801],{},"    var pinyin = []string{\"guangdong\", \"hainan\", \"fujian\", \"taiwan\", \"a\"}\n",[47,803,804],{"class":49,"line":110},[47,805,60],{"emptyLinePlaceholder":59},[47,807,808],{"class":49,"line":116},[47,809,810],{},"    han, err := com.NewPinyinHan().Run(\"..\u002Fdata\u002Fpinyin_dict.txt\", pinyin)\n",[47,812,813],{"class":49,"line":122},[47,814,60],{"emptyLinePlaceholder":59},[47,816,817],{"class":49,"line":128},[47,818,223],{},[47,820,821],{"class":49,"line":134},[47,822,823],{},"        t.Error(err)\n",[47,825,826],{"class":49,"line":140},[47,827,828],{},"        return\n",[47,830,831],{"class":49,"line":145},[47,832,178],{},[47,834,835],{"class":49,"line":151},[47,836,60],{"emptyLinePlaceholder":59},[47,838,839],{"class":49,"line":157},[47,840,841],{},"    t.Log(han)\n",[47,843,844],{"class":49,"line":163},[47,845,137],{},[10,847,848],{},"输出结果：",[10,850,851],{},[19,852,855],{"href":853,"rel":854},"https:\u002F\u002Fcdn.jsdelivr.net\u002Fgh\u002Ftomdehub\u002Fresources\u002Fbe\u002Ff16d677e3033c8b5d8288f0dbd586d61\u002Fblog_6038391571834635959\u002F2026-07\u002F2026070317_RT3ttEBDR.png",[23],[856,857],"img",{"alt":42,"src":853},[10,859,860],{},"说句题外话，其实字典可以根据业务在做一些轻量化定制，例如我的项目里，只有检索功能才用到，我会根据文本内容用到一些分词器、拼音转换器生成自定义数据写进字典里。",[862,863,864],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":42,"searchDepth":56,"depth":56,"links":866},[],"2026-07-03 17:01:34","md",{"tags":870,"image":853},[871,872],"拼音汉字转换","Golang","\u002Fyehangzhou\u002Fposts\u002Fgo-pinyin-to-han","---\ntitle: 'Go语言实现拼音转化为汉字'\ndescription: ''\ndate: 2026-07-03 17:01:34\ntags: ['拼音汉字转换', 'Golang']\nimage: 'https:\u002F\u002Fcdn.jsdelivr.net\u002Fgh\u002Ftomdehub\u002Fresources\u002Fbe\u002Ff16d677e3033c8b5d8288f0dbd586d61\u002Fblog_6038391571834635959\u002F2026-07\u002F2026070317_RT3ttEBDR.png'\n---\n\n预先说明：以项目名为 x 作为示例\n\n第一步：在GitHub找个汉字拼音字典（随便找了一个输入法项目的字典）\n\n[https:\u002F\u002Fgithub.com\u002FMobtgZhang\u002FLingJian-Pinyin\u002Fblob\u002Fmain\u002Fdata\u002Fpinyin\\_dict.txt](https:\u002F\u002Fgithub.com\u002FMobtgZhang\u002FLingJian-Pinyin\u002Fblob\u002Fmain\u002Fdata\u002Fpinyin_dict.txt)\n\n第二步：把字典下载下来放在项目里，例如：data\u002Fpinyin\\_dict.txt\n\nx\u002Fdata\u002Fpinyin\\_dict.txt\n\n第三步：创建 com\u002Fpinyin\\_han.go 文件，把代码复制进去\n\nx\u002Fcom\u002Fpinyin\\_han.go\n\n```go\npackage com\n\nimport (\n\t\"bufio\"\n\t\"os\"\n\t\"strings\"\n\t\"sync\"\n)\n\ntype PinyinHan struct {\n\tpyToHan     map[string][]string\n\tabbrToHan   map[string][]string \u002F\u002F 简拼映射\n\tnoToneToHan map[string][]string \u002F\u002F 无声调映射\n\tmutex       sync.RWMutex\n}\n\nfunc NewPinyinHan() *PinyinHan {\n\treturn &PinyinHan{\n\t\tpyToHan:     make(map[string][]string),\n\t\tabbrToHan:   make(map[string][]string),\n\t\tnoToneToHan: make(map[string][]string),\n\t}\n}\n\nfunc (p *PinyinHan) LoadDictionary(filename string) error {\n\tp.mutex.Lock()\n\tdefer p.mutex.Unlock()\n\n\tfile, err := os.Open(filename)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer func(file *os.File) {\n\t\t_ = file.Close()\n\t}(file)\n\n\tscanner := bufio.NewScanner(file)\n\tfor scanner.Scan() {\n\t\tline := strings.TrimSpace(scanner.Text())\n\t\tif line == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tparts := strings.Fields(line)\n\t\tif len(parts) >= 2 {\n\t\t\tpinyin := parts[0]\n\t\t\thanzi := parts[1]\n\n\t\t\t\u002F\u002F 标准拼音映射\n\t\t\tp.pyToHan[pinyin] = append(p.pyToHan[pinyin], hanzi)\n\n\t\t\t\u002F\u002F 构建简拼映射\n\t\t\tabbr := p.getAbbreviation(pinyin)\n\t\t\tp.abbrToHan[abbr] = append(p.abbrToHan[abbr], hanzi)\n\n\t\t\t\u002F\u002F 构建无声调映射\n\t\t\tnoTone := p.removeTone(pinyin)\n\t\t\tp.noToneToHan[noTone] = append(p.noToneToHan[noTone], hanzi)\n\t\t}\n\t}\n\n\treturn scanner.Err()\n}\n\nfunc (p *PinyinHan) getAbbreviation(pinyin string) string {\n\tsyllables := strings.Fields(pinyin)\n\tvar abbr strings.Builder\n\tfor _, syl := range syllables {\n\t\tif len(syl) > 0 {\n\t\t\tabbr.WriteByte(syl[0])\n\t\t}\n\t}\n\treturn abbr.String()\n}\n\nfunc (p *PinyinHan) removeTone(pinyin string) string {\n\t\u002F\u002F 简单的声调数字去除\n\tresult := make([]byte, 0, len(pinyin))\n\tfor i := 0; i \u003C len(pinyin); i++ {\n\t\tif pinyin[i] \u003C '1' || pinyin[i] > '4' {\n\t\t\tresult = append(result, pinyin[i])\n\t\t}\n\t}\n\treturn string(result)\n}\n\nfunc (p *PinyinHan) Convert(pinyin string) []string {\n\tp.mutex.RLock()\n\tdefer p.mutex.RUnlock()\n\n\t\u002F\u002F 优先级：精确匹配 > 无声调匹配 > 简拼匹配\n\tif result, exists := p.pyToHan[pinyin]; exists {\n\t\treturn result\n\t}\n\n\tnoTone := p.removeTone(pinyin)\n\tif result, exists := p.noToneToHan[noTone]; exists {\n\t\treturn result\n\t}\n\n\tif result, exists := p.abbrToHan[pinyin]; exists {\n\t\treturn result\n\t}\n\n\treturn nil\n}\n\nfunc (p *PinyinHan) Run(dictPath string, pinyin []string) ([]string, error) {\n\terr := p.LoadDictionary(dictPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar out = make([]string, 0)\n\tfor _, v := range pinyin {\n\t\tv = strings.ReplaceAll(v, \" \", \"\")\n\t\tresult := p.Convert(v)\n\t\tfor _, s := range result {\n\t\t\tout = append(out, s)\n\t\t}\n\t}\n\treturn out, nil\n}\n```\n\n第四步：直接调用（以Test为例）\n\nx\u002Ftest\u002Fpinyin\\_han\\_test.go\n\n```go\npackage test\n\nimport (\n\t\"testing\"\n\t\"x\u002Fcom\"\n)\n\nfunc TestPinyinHan(t *testing.T) {\n\n\tvar pinyin = []string{\"guangdong\", \"hainan\", \"fujian\", \"taiwan\", \"a\"}\n\n\than, err := com.NewPinyinHan().Run(\"..\u002Fdata\u002Fpinyin_dict.txt\", pinyin)\n\n\tif err != nil {\n\t\tt.Error(err)\n\t\treturn\n\t}\n\n\tt.Log(han)\n}\n```\n\n输出结果：\n\n[![](https:\u002F\u002Fcdn.jsdelivr.net\u002Fgh\u002Ftomdehub\u002Fresources\u002Fbe\u002Ff16d677e3033c8b5d8288f0dbd586d61\u002Fblog_6038391571834635959\u002F2026-07\u002F2026070317_RT3ttEBDR.png)](https:\u002F\u002Fcdn.jsdelivr.net\u002Fgh\u002Ftomdehub\u002Fresources\u002Fbe\u002Ff16d677e3033c8b5d8288f0dbd586d61\u002Fblog_6038391571834635959\u002F2026-07\u002F2026070317_RT3ttEBDR.png)\n\n说句题外话，其实字典可以根据业务在做一些轻量化定制，例如我的项目里，只有检索功能才用到，我会根据文本内容用到一些分词器、拼音转换器生成自定义数据写进字典里。\n",{"title":5,"description":42},"yehangzhou\u002Fposts\u002Fgo-pinyin-to-han","N_xhMJG7wSo2hO9sHI_5yKPIkmlHkSk7C8zH2HvkkTw",1784926490642]