随笔 - 404  文章 - 0  评论 - 1037  阅读 - 136万 

(作者:finallyly 出处:博客园 转载请注明作者和出处)

   把汉字转换成拼音,实际上是一个非技术活,无外乎查表而已。可能由于汉字拼音转换表资源比较宝贵的缘故,网络上开源的转换程序比较少。另外,网络上给出的码表,可能不能覆盖全部的多音字,生僻字,所以基于此类码表写成的程序,也就有一定的局限性。

  本文给出一份完毕的,将汉字转换成无声调标注的拼音的设计思路、全部代码并且给出一份在一定程度上可用的汉字拼音转换表。

首先指出本文部分参考了原创  《Python返回汉字的汉语拼音(原创) 》的汉字拼音转换表以及大概思路。

下面步入正轨

汉语拼音转换表的物理存储格式:(汉字+空格+汉字对应的拼音,多个候选读音用哪个空格隔开)

@XBVHWN([EIW8S89[C@BD1Z

程序中的转换表用MAP保存,其数据格式为map<wstring,vector<string>>,wstring:键值;vector<string> 候选读音

1. 将硬盘中的码表读入内存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
void StringManipulation::FormatPinYinMap(map<wstring,vector<string >>&hptable)
{
    ifstream ifile("mycodebook.txt");
     
    string line;
    while (getline(ifile,line))
    {
        if (!line.empty())
        {   wstring wsResult=String2Wstring(line);
            vector<wstring> goodWordstemp;
            boost::split(goodWordstemp,wsResult,boost::is_any_of(" "));
            wstring mykey=goodWordstemp[0];
            vector<string>myval;
            for(vector<wstring>::iterator it=goodWordstemp.begin()+1;it!=goodWordstemp.end();it++)
            
                myval.push_back(Wstring2String(*it));
                 
 
 
 
            }
            if (!hptable.count(mykey))
            {
                hptable[mykey]=myval;
            }
 
 
        }
 
 
 
 
 
    }
 
}

 

2. 将单个汉字转换成拼音的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
vector<string>StringManipulation::HZ2Py(wstring character,map<wstring,vector<string> >& hptable)
{
 
    vector<string>candidates;
    if (hptable.count(character))
    {
        candidates=hptable[character];
 
    }
    else
    {
        candidates.push_back("[A-Z]+");
 
    }
    return candidates;
 
}
1
3. 将汉字字符串转换成对应的拼音字符串(重点函数)
1
此份代码可以将任意汉字串转换成拼音。但是,工作侧重点是将汉语人名转换成拼音形式,从而构造启发式查询。
1
考虑到多音字,生僻字等多种情形,为了让转换成的拼音字符串更具鲁棒性,我们在转换后的拼音串中加入了若干正则表达式
1
比如我们将“刘禹锡”转换成”LIU.*?YU.*?XI”。这样形成的拼音字符串既可以和含有“liuyuxi”网页匹配,又可以和含有”LIU YUXI”网页匹配。
1
汉语字符串中含有多音字的时候,可以形成多个候选读音。由于我们事先并不知道那些字是多音字,所有我们不可能事先确定一个汉字串究竟有多少种候选读音。
1
这里采用的办法是:生成一个图来表示每个汉字对应的后续读音,以及这些读音之间的有向连接关系。
1
然后用求有向图上任意两点间的所有路径的算法见《<a href="http://www.cnblogs.com/finallyliuyu/archive/2011/04/18/2019534.html">求两点之间所有路径的算</a>法》,求出一个汉字字符串所对应的所有候选读音。
1
  
1
<a href="http://images.cnblogs.com/cnblogs_com/finallyliuyu/201105/201105162159215935.png"><img title="image" style="border: 0; display: inline" height="78" alt="image" src="https://images.cnblogs.com/cnblogs_com/finallyliuyu/201105/201105162159221725.png" width="244" border="0"></a>
1
  

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/************************************************************************/
/*获得一汉字字符串的拼音串                                                                     */
/************************************************************************/
vector<string> StringManipulation::Han2Py(string shan,map<wstring,vector<string>>&hptable)
{
    vector<string>result;
    GraphRepresentation gr;
    gr.Vertex[0]="@";
    int mycount=0;//是否添加“正则边”
    int prevsize=0;//上一个汉字有几个读音
    int laslabel=0;//上一次节点编号的最大值
    if (!shan.empty())
    {
        wstring whan=String2Wstring(shan);
        for (wstring::iterator it=whan.begin();it!=whan.end();it++)
        {
            wstring tmp;
            tmp.assign(1,*it);
            vector<string>tmpcandidates=HZ2Py(tmp,hptable);
            if(mycount==0)
            {
                for (int i=0;i<tmpcandidates.size();i++ )
                {
                    gr.Vertex[i+laslabel+1]=tmpcandidates[i];
                    gr.GraphR[make_pair(0,i+laslabel+1)]="&";
 
                }
                prevsize=tmpcandidates.size();
                laslabel=tmpcandidates.size();
 
            }
            else
            {
                for (int i=0;i<tmpcandidates.size();i++ )
                {
                    gr.Vertex[i+laslabel+1]=tmpcandidates[i];
                    for (int j=laslabel;j>laslabel-prevsize;j--)
                    {
                        gr.GraphR[make_pair(j,i+laslabel+1)]=".*?";
                    }
                     
 
                }
                laslabel+=tmpcandidates.size();
                prevsize=tmpcandidates.size();
                 
 
 
 
 
            }
            mycount++;
 
        }
        gr.Vertex[laslabel+1]="@";
        for (int j=laslabel;j>laslabel-prevsize;j--)
        {
            gr.GraphR[make_pair(j,laslabel+1)]="&";
        }
        vector<vector<int>>paths;
        gr.GetPaths(paths,0,laslabel+1);
        for (vector<vector<int>>::iterator it=paths.begin();it!=paths.end();it++)
        
            deque<int>tmpque;
            string singlecandidate;
            for (vector<int>::reverse_iterator rit=it->rbegin();rit!=it->rend();rit++)
            {  
                tmpque.push_back(*rit);
                 
                if (tmpque.size()==2)
                {
                    int tmp1=tmpque.front();
                    tmpque.pop_front();
                    singlecandidate+=gr.Vertex[tmp1];
                    int tmp2=tmpque.front();
                    string edge=gr.GraphR[make_pair(tmp1,tmp2)];
                    singlecandidate+=edge;
                     
 
                 
                }
                 
                 
                     
                 
                 
        
            TrimString(singlecandidate,"@");
            TrimString(singlecandidate,"&");
            result.push_back(singlecandidate);
        }
 
 
 
    }
     
  return result;
     
}
1
  
1
  
1
  
1
其他辅助函数见<a href="http://www.cnblogs.com/finallyliuyu/archive/2011/05/16/2048138.html">《小谈汉字转换成拼音辅助函数和辅助类》</a>
1
汉字2拼音转换表 https://files.cnblogs.com/finallyliuyu/mycodebook.rar
1
主调函数:
1
StringManipulation strp;<br> map<wstring,vector<string>>h2ptable;<br> strp.FormatPinYinMap(h2ptable);<br>vector<string>result=strp.Han2Py("陈阿娇",h2ptable);<br> for (vector<string>::iterator it=result.begin();it!=result.end();it++)<br> {<br>  cout<<*it<<endl;<br> }
1
效果:
1
  
1
  
1
  
1
  
1
  
1
  
1
  
posted on   finallyly  阅读(14904)  评论(11编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
历史上的今天:
2010-05-16 scipy 知识碎片
点击右上角即可分享
微信分享提示