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

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

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

        还好,在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.
#
#
3007	ling2
4E00	yi1
4E01	ding1
4E02	kao3
4E03	qi1
4E04	shang4	shang3
4E05	xia4
4E06
4E07	wan4	mo4
4E08	zhang4
4E09	san1
4E0A	shang4	shang3
4E0B	xia4
4E0C	ji1
4E0D	bu4
4E0E	yu3	yu4
4E0F	mian3

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

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

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

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

        以下是头文件:

/********************************************************************
filename: 	Hanzi2Pinyin.h
created:	2012-06-07
author:		firehood

purpose:	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.cpp
created:	2012-06-07
author:		firehood

purpose:	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!


 

 

 

       

  • 6
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
在 JavaScript 中,可以使用第三方库来实现汉字拼音的功能。其中比较流行的库是 pinyin.js。 以下是使用 pinyin.js 库进行汉字拼音的详细教程: 1.引入 pinyin.js 库 在 HTML 文件中引入 pinyin.js 库。 ```html <script src="https://cdn.bootcdn.net/ajax/libs/pinyinjs/0.3.3/pinyin.core.js"></script> ``` 2.编写 JavaScript 代码 首先,需要获取要换成拼音汉字字符串。 ```javascript let chineseStr = "你好世界"; ``` 然后,使用 pinyin.js 库的 `getFullChars()` 方法将汉字换成全拼。 ```javascript let pinyinStr = pinyin.getFullChars(chineseStr); ``` 如果只需要获取汉字的首字母拼音,可以使用 `getFirstChars()` 方法。 ```javascript let pinyinStr = pinyin.getFirstChars(chineseStr); ``` 如果需要获取汉字的简拼,可以使用 `getShortChars()` 方法。 ```javascript let pinyinStr = pinyin.getShortChars(chineseStr); ``` 最后,将换后的拼音字符串输出。 ```javascript console.log(pinyinStr); // 输出:nǐ hǎo shì jiè ``` 完整的 JavaScript 代码如下: ```javascript let chineseStr = "你好世界"; let pinyinStr = pinyin.getFullChars(chineseStr); console.log(pinyinStr); // 输出:nǐ hǎo shì jiè ``` 需要注意的是,pinyin.js 库只能将汉字换成拼音,对于其他语种的字符将不会进行换。同时,由于拼音存在多音字的情况,换结果可能存在歧义,需要根据实际情况进行处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值