汉字转化为拼音,支持多音字

来源:互联网 发布:模型算法生成 编辑:程序博客网 时间:2024/04/26 20:32

        最近需要在车机上增加蓝牙电话薄功能,其中最重要的一个功能是需要通过人名的拼音或首字母来查询电话薄,比较好的一个实现方式是首先将电话薄中中文姓名转化为拼音和拼音对应首字母,然后跟用户输入的拼音字符串进行匹配,如果匹配成功,则将电话薄中匹配的记录显示出来。所以第一个问题是解决汉字转化为拼音的问题。如何将汉字转化为拼音呢?

        最好的期望是有一张汉字对应拼音的一个列表,里面列举出每个汉字对应的拼音,通过这个列表,能够比较快速的得到某个汉字对应的拼音,考虑到存在多音字的问题,一个汉字可能对应多个拼音,所以这个表的设计必须是一对多的关系,分析到这里,如何实现这个汉字对应拼音的列表是关键。

        还好,在Google上找到一份Unicode汉字对应的拼音列表,这里要感谢原作者Koichi Yasuoka的辛苦整理和共享。

        截取文件的部分内容如下:

##Name:            Unicode Pinyin table#Unicode version: 1.1#Table version:   0.496#Table format:    Format A#Date:            18 August 1997#Author:          Koichi Yasuoka <yasuoka@kanji.zinbun.kyoto-u.ac.jp>##General notes:##This table contains the data on how Unicode Hanzi characters#are pronounced in P.R.China.  This table was originally based#on "TONEPY.tit" by Yongguang Zhang <ygz@cs.purdue.edu>.  Here#the author expresses his appreciation to Christian Wittern#<cwittern@conline.central.de>, Jim Breen <jwb@rdt.monash.edu.au>,#and Jack Halpern <jhalpern@super.win.or.jp>.##Format:  Six tab-separated columns#         Column #1 is the Unicode (in hex)#         Columns #2 to #6 are Pinyin (tone '5' means Qingsheng)##The entries are in Unicode order.##3007ling24E00yi14E01ding14E02kao34E03qi14E04shang4shang34E05xia44E064E07wan4mo44E08zhang44E09san14E0Ashang4shang34E0Bxia44E0Cji14E0Dbu44E0Eyu3yu44E0Fmian3

        文件按照Unicode编码顺序进行整理,每行第一列是Unicode汉字的16进制编码,第二列到第N列是汉字对应所有的拼音字符串,拼音后面的1--5数字为拼音的声调。

        为什么要采用Unicode而不使用GB2312,因为GB2312收录的汉字只包含了中国大陆99.75%的使用频率,对于一些人名、古汉语等方面出现的罕用字,GB2312不能表示示。而Unicode收录的汉字会比较全一些,包括一些古体字和生僻字都能表示 。 所以这里采用Uincode,这样电话薄中的人名即使含有一些生僻的汉字,也能处理。

        通过该表,可以很方便通过汉字的Unicode编码查询到对应的拼字字符串和首字母,即使是多音字也能处理。

        这里,基于该表实现了一个Unicode汉字转拼音的类,可以方便的将汉字字符串转化为拼音或拼音首字母。

        以下是头文件:

/********************************************************************filename: Hanzi2Pinyin.hcreated:2012-06-07author:firehoodpurpose:Unicode汉字转化为拼音*********************************************************************/#pragma once#include <windows.h>#include <vector>#include <string>using namespace std;typedef vector<string>  PinyinList;typedef vector<char>    FirstLetterList;class CHanzi2Pinyin{public:CHanzi2Pinyin(void);~CHanzi2Pinyin(void);public:/********************************************************** 函数名:Hanzi2Pinyin功能:  单个Unicode汉字字符转化为拼音字符串参数: [in]wch:                 Unicode汉字字符[out]pinyinList:         转化后的拼音字符串,因为汉字存在多音字,转换后的拼音字串存在PinyinList表中[out]firstLetterList:    汉字对应拼音的首字母列表(以大写字母表示)返回值: TRUE:  成功  FALSE:失败 ***********************************************************/  BOOL Hanzi2Pinyin(const wchar_t wch, PinyinList& pinyinList,FirstLetterList &firstLetterList);/********************************************************** 函数名:Hanzi2Pinyin功能:  Unicode汉字字符串转化为拼音字符串参数: [in]wch:                 Unicode汉字字符串[out]pinyinList:         转化后的拼音字符串,因为汉字存在多音字,转换后的拼音字串存在PinyinList表中                         如果汉字中存在多音字,会将拼音字符串的所有可能组合列举出来。 比如对于汉字"行长重"转化后的拼音字符串会有以下8中组合情况。 "xing chang zhong","xing chang chong", "xing zhang zhong","xing zhang chong", "hang chang zhong","hang chang chong", "hang zhang zhong","hang zhang chong". 每个拼音之间用空格分隔[out]firstLetterList:    汉字对应拼音的首字母字符串列表(以大写字母表示)                         比如对于汉字"行长重"转化后的拼音字符串会有以下8中组合情况。                         "XCZ","XCC",                         "XZZ","XZC",                         "HCZ","HCC",                         "HZZ","HZC"返回值: TRUE:  成功  FALSE:失败 ***********************************************************/  BOOL Hanzi2Pinyin(const wchar_t *wstr,int len, PinyinList& pinyinList,PinyinList &firstLetterList);private:BOOL Init();void Uninit();private:    FILE* m_pFile;UINT  m_nBasePos;};


           源文件如下:

/********************************************************************filename: Hanzi2Pinyin.cppcreated:2012-06-07author:firehoodpurpose:Unicode汉字转化为拼音*********************************************************************/#include "stdafx.h"#include "Hanzi2Pinyin.h"#include <algorithm>#define UINCODE_HANZI_START    0x4E00 #define UINCODE_HANZI_END      0x9FA5// 定义资源文件路径#define HANZI2PIN_RES_PATH     "E:\\zfhu\\Uni2Pinyin\\Uni2Pinyin.DAT"//"E:\\资料\\Hanzi2Pinyin\\Uni2Pinyin.DAT"CHanzi2Pinyin::CHanzi2Pinyin(void):m_pFile(NULL),m_nBasePos(0){Init();}CHanzi2Pinyin::~CHanzi2Pinyin(void){Uninit();}BOOL CHanzi2Pinyin::Init(){char strline[64] = {0};int nPos = 0;// 如果之前有初始化,先卸载if(m_pFile){Uninit();}// 打开Unicode拼音编码表m_pFile = fopen(HANZI2PIN_RES_PATH, "rb");  if(m_pFile == NULL){return FALSE;}BOOL bRet = FALSE;// 读取一行,直到找到编码的起始位置while(fgets(strline,sizeof(strline),m_pFile))  {  if(strtoul(strline,NULL,16) == UINCODE_HANZI_START){m_nBasePos = nPos;bRet = TRUE;break;}nPos = ftell(m_pFile);}  return bRet;}void CHanzi2Pinyin::Uninit(){if(m_pFile)fclose(m_pFile);m_nBasePos = 0;}BOOL CHanzi2Pinyin::Hanzi2Pinyin(const wchar_t wch,PinyinList& pinyinList,FirstLetterList &firstLetterList){// 判断字符是否为汉字if((wch < UINCODE_HANZI_START) || (wch > UINCODE_HANZI_END)){// 不是汉字,直接返回return FALSE;}if(m_pFile == NULL){// 初始化if(!Init()){return FALSE;}}// 移动文件指针到表的起始位置fseek(m_pFile, m_nBasePos, SEEK_SET);// 计算行数int lineCount = wch - UINCODE_HANZI_START;char strline[64] = {0};// 读取lineCount行while(lineCount--){fgets(strline,sizeof(strline),m_pFile);}    memset(strline,0,sizeof(strline));    fgets(strline,sizeof(strline),m_pFile); // 判断是否定位到正确位置if(strtoul(strline,NULL,16) != wch){return FALSE;}string pinyinStr = "";BOOL bFindPinyin = FALSE;UINT i = 0;for(i = 4;i<strlen(strline);i++){// 判断字符是否为拼音字符,拼音字符必须在a~z之间if(strline[i]>='a' && strline[i]<='z') {bFindPinyin = TRUE;pinyinStr += strline[i];}else // 不是拼音字符{if(bFindPinyin) {// 查找vector是否已存在该拼音字串,没有则添加if(std::find(pinyinList.begin(),pinyinList.end(),pinyinStr) == pinyinList.end()){// 存在将拼音字串存入到vector中pinyinList.push_back(pinyinStr);}if(std::find(firstLetterList.begin(),firstLetterList.end(),pinyinStr[0]-32)==firstLetterList.end()){// 将拼音首字母存入到vector中firstLetterList.push_back(pinyinStr[0]-32);}pinyinStr = "";bFindPinyin = FALSE;}}}if(bFindPinyin){   // 查找vector是否已存在该拼音字串,没有则添加if(std::find(pinyinList.begin(),pinyinList.end(),pinyinStr) == pinyinList.end()){// 存在将拼音字串存入到vector中pinyinList.push_back(pinyinStr);}if(std::find(firstLetterList.begin(),firstLetterList.end(),pinyinStr[0]-32)==firstLetterList.end()){// 将拼音首字母存入到vector中firstLetterList.push_back(pinyinStr[0]-32);}}return TRUE;}// 定义转化后拼音列表的最大长度(如果要转化的汉字字串中不存在多音字,则转换后拼音字串只有一行;若存在多音字,则将所有可能的拼音组合列举出来)static const UINT MAX_PINYINLISTCOUNT = 8;BOOL CHanzi2Pinyin::Hanzi2Pinyin(const wchar_t *wstr,int len, PinyinList& pinyinList,PinyinList &firstLetterList){    // 参数有效性检查if(wstr == NULL && len <=0) {return FALSE;}string pinyinStr[MAX_PINYINLISTCOUNT],tempPinyinStr[MAX_PINYINLISTCOUNT];        // 存放一组汉字对应的拼音字符串string firstletterStr[MAX_PINYINLISTCOUNT],tempfirstLetter[MAX_PINYINLISTCOUNT]; // 存放一组汉字对应的拼音首字母字符串int nlistCountPY = 0, nlistCountFL = 0; int indexPY = 0,indexFL = 0;// 缓存单个汉字的拼音字符串列表,一个汉字可能能有多个拼音    PinyinList *singlePinyinList = new PinyinList[len];FirstLetterList *firstLettterList = new FirstLetterList[len];for(int i=0;i<len;i++){// 将单个汉字转化为拼音if(!Hanzi2Pinyin(wstr[i],singlePinyinList[i],firstLettterList[i]))continue;if(nlistCountPY == 0){for(UINT n = 0;n<singlePinyinList[i].size();n++){if(indexPY >= MAX_PINYINLISTCOUNT){break;}pinyinStr[indexPY++] = singlePinyinList[i][n];if(n<firstLettterList[i].size())firstletterStr[indexFL++] = firstLettterList[i][n];}}else{// 拷贝到临时缓存中,用以做拼接处理            for(int m = 0; m<nlistCountPY; m++){tempPinyinStr[m] = pinyinStr[m];tempfirstLetter[m] = firstletterStr[m];}for(int m = 0; m<nlistCountPY; m++){for(UINT n = 0;n<singlePinyinList[i].size();n++){if(indexPY >= MAX_PINYINLISTCOUNT){break;}pinyinStr[indexPY++] = tempPinyinStr[m] + " " + singlePinyinList[i][n];if(m<nlistCountFL && n<firstLettterList[i].size()){firstletterStr[indexFL++] = tempfirstLetter[m] + firstLettterList[i][n];}}}}nlistCountPY = indexPY;nlistCountFL = indexFL;indexPY = 0;indexFL = 0;}for(int i=0;i<nlistCountPY;i++){pinyinList.push_back(pinyinStr[i]);}for(int i=0;i<nlistCountFL;i++){firstLetterList.push_back(firstletterStr[i]);}delete[] singlePinyinList;delete[] firstLettterList;return TRUE;}

        基于CHanzi2Pinyin类实现了一个汉字转拼音的工具,测试效果如下:

1. 汉字转化为拼音

 

2. 汉字转化为拼音首字母

 


          最后,在次感谢Unicode汉字转拼音文件的作者Koichi Yasuoka!