汉字转【pinyin】
引言
github地址:aizuyan/pinyin
无意中看到了overtrue/pinyin这个项目,感觉很有意思,
这个项目做了这么一件事情:
将汉字转化为拼音
刚看到这里是不是觉得没什么难度,没什么意思?您不妨接着往下看。要是只是将汉字转为拼音好像
很容易就实现了,但是要是给转换之后的汉字带上音调呢,这样难度就很大了,因为汉字博大精深,
其中一方面就表现在多音字,同样一个字在不同的语句场景下,音调是不一样的。看到这里你在考
虑下如何处理?
替换的时候首先将常用的词组替换了,比如短语、成语、常用的词语,这些词语替换的时候按照常
用程度由高到低排序。
接着对剩余的未被替换的汉字进行替换,这里直接按照所有汉字和拼音的映射,没有特定顺序。
如果是姓名,首先对姓氏进行一遍特定替换,姓氏的声调可能和常用的不一致。
除了项目的想法很棒之外,还有一个大难题要解决,就是收集词语,姓氏等,这里我直接使用了安正 超的项目中的数据,再次也该写下安前辈。
我的这个项目可以说是很大程度上是安前辈的overtrue/pinyin项目的另一个版本。
设计
这个项目中会用到一个数据结构,单链表,用来存储拼音、汉字对应关系的数据,一开始想着使用Bu cket数据结构,后来觉得,这个数据结构体里面冗余的信息太多了,也不是很符合我预想的数据结构,
so,最后使用了下面的数据结构:
typedef struct mylist {
char *key; //词语、成语或者单个汉字
char *val; //对应的拼音,拼音前面都有一个制表符`\t`
struct mylist *next; //指向下一个汉字拼音结构体
} MyList;
除此之外,我还考虑了性能问题,安前辈php版本的有个固有的缺陷,每次请求都要去加载一遍数据文
件,大概有600~700kb左右,转换为数组,元素个数为40000~50000个左右,每次请求都会分配、释放这部分内
存。而且这个过程会有大量的计算过程(查找、替换),这也是php很不擅长的,如果用c语言会好很多。
因此,我就使用了PHP扩展,在模块初始化的时候,将所有配置数据载入内存,如果是fast-cgi模式,
不用每次请求都加载一遍配置数据,只在进程启动的时候加载一遍。计算的话没有找到php里面比较合适的
函数,字节写了查找替换的函数。
还有就是如何读取配置文件数据了,我采用了下面的数据格式存储每一个汉-拼对“,csv个格式,每一行
第一列是短语、词语或者汉字,第二列是拼音,每个拼音之间使用制表符\t分割,这样读取、进一步处理
就很方便了
汉字, han zi
......
{汉字|词语|短语}, pin yin
实现
实现部分,挑几个主要的函数出来:
首先是给链表中添加汉字拼音结构体的函数,这里有个地方要注意,这里使用了c语言原声的malloc和strdup,这是因为这个变量是全局的,不会随着请求的结束而销毁,而且也不会区分线程,因为所有的
线程都只会读取变量中的内容,所有的线程共享一套变量就可以了。
MyList *pinyin_list_append(MyList *last, const char *key, const char *value)
{
MyList *element = (MyList *)malloc(sizeof(MyList));
char *newKey = strdup(key);
char *newVal = strdup(value);
element->key = newKey;
element->val = newVal;
element->next = NULL;
last->next = element; return element;
}
下面这个函数是从一行通过逗号分隔的字符串中取出逗号前面的部分作为汉字部分。
const char *get_key_from_line(const char *line, char *ret)
{
int i = ;
while(*line)
{
if(*line != ',')
{
ret[i] = *line;
}else {
break;
}
i++;
line++;
}
ret[i] = '\0';
return ret;
}
下面是同一行中分离出拼音部分:
const char *get_val_from_line(const char *line, char *ret)
{
int i = ;
int flag = ;
while(*line)
{
if(*line == '\n')
{
break;
}
if(*line == ',')
{
flag = ;
line++;
continue;
}else if(!flag) {
line++;
continue;
}
ret[i] = *line;
i++;
line++;
}
ret[i] = '\0';
return ret;
}
下面是最重要的一个,替换字符换函数,from是要替换的字符串,to是要替换为的字符串,str是原始字符串,ret是临时字符串,会保存临时的结果,is_name表示是否是姓名,
如果是姓名,只替换一次。
void str_replace(const char *from, const char *to, char *str, char *ret, zend_bool is_name)
{
int pos = ,
fromLen = strlen(from),
flag = ;
char *tmp = NULL,
*strTmp = str;
while(tmp = strstr(str, from))
{
pos = tmp - str;
strncat(ret, str, pos);
strcat(ret, to);
str = tmp + fromLen;
flag = ;
if(is_name)
break;
} strcat(ret, str);
if( == flag)
{
memcpy(strTmp, ret, strlen(ret));
strTmp[strlen(ret)] = '\0';
}
}
使用
只通过一个函数和标志位来实现,使用起来也是很方便的:
使用的时候可以参考github中的README.md,里面有详细的编译配置细节。
例子
print_r(chinese_to_pinyin("彪悍的人生不需要解释!"));
输出内容,带音标、带标点(标点和拼音挤在一起)
Array
(
[] => biāo
[] => hàn
[] => de
[] => rén
[] => shēng
[] => bù
[] => xū
[] => yào
[] => jiě
[] => shì!
)
print_r(chinese_to_pinyin("彪悍的人生不需要解释!", PINYIN_NONE|PINYIN_FORMAT_EN));
输出结果,不带音标,标点符号单独开了:
Array
(
[] => biao
[] => han
[] => de
[] => ren
[] => sheng
[] => bu
[] => xu
[] => yao
[] => jie
[] => shi
[] => !
)
print_r(chinese_to_pinyin("燕睿涛"));
print_r(chinese_to_pinyin("燕睿涛", PINYIN_ISNAME));
print_r(chinese_to_pinyin("罗永浩", PINYIN_ISNAME));
输出内容,可以看出PINYIN_ISNAME这个标志位还是很有用的,
rray
(
[] => yàn
[] => ruì
[] => tāo
)
Array
(
[] => yān
[] => ruì
[] => tāo
)
Array
(
[] => luō
[] => yǒng
[] => hào
)
初次之外,还有些关于标志位的使用规律:
PINYIN_NONE、PINYIN_UNICODE两个是对立的,使用前者没有音调,使用后者有音调,默认是前者。
PINYIN_TRIM、PINYIN_FORMAT_EN、PINYIN_FORMAT_CH是对立的,第一个清除所有标点、第二个
使用英文标点,第三个使用中文标点
PINYIN_ISNAME 如果设置了这个标志位,会使用姓氏的规则去解析读音。
总结
这是第二个PHP扩展了,这次写起来跟1年前相比容易了许多,错误也比较少了,继续努力吧~
不要停止学习的脚步,提高自身核心竞争力。
汉字转【pinyin】的更多相关文章
- 使用pinyin4j汉字转pinyin
引入maven依赖<dependencies> <dependency> <groupId>com.belerweb</groupId> <art ...
- 基于SolrCloud的内容搜索和热点推送
➠更多技术干货请戳:听云博客 什么是热点 我认为热点有时效性和受众面 用户关注从低到高再到低的内容 .有公共热点和分类热点.例如医辽养老全民关注,科技汽车等只有特定的人群关注. 推送的条件 搜索频次达 ...
- solr入门之搜索建议的几种实现方式和最终选取实现思路
上篇博客中我简单的讲了下solr自身的suggest模块来实现搜索建议.但是今天研究了下在solr自身的suggest中添加进去拼音来智能推荐时不时很方便.在次从网上搜集和整理思考了下该问题的解决. ...
- select2 全拼以及首字母
转自:https://blog.csdn.net/kanhuadeng/article/details/78475317 具体实现方法为: 首先需要在网上下载select2的源码,并引入到项目中,具体 ...
- solr入门之pinyin4j源代码改写动态加入扩展词及整合进war项目中
1.初始化时载入用户定义的字典 package net.sourceforge.pinyin4j; import net.sourceforge.pinyin4j.multipinyin.Trie; ...
- 搜索引擎keyword智能提示的一种实现
问题背景 搜索关键字智能提示是一个搜索应用的标配.主要作用是避免用户输入错误的搜索词,并将用户引导到相应的关键词上,以提升用户搜索体验. 美团CRM系统中存在数以百万计的商家,为了让用户高速查找到目标 ...
- [功能帮助类] C#取汉字拼音的首字母PinYin帮助类 (转载)
点击下载 PinYin.rar 主要功能就是取汉字拼音的首字母,只要你输入一个汉字,或者是多个汉字就会取出相应的道字母,主要是方便查询使用的 /// <summary> /// 编 码 人 ...
- 【Python】 汉字转化汉语拼音pinyin
pinyin pinyin模块是github上一个小项目,在github.com/cleverdeng/pinyin.py上面可以下到源码.衷心感谢那些为这个模块做出贡献的人来方便我们[鞠躬] 安装: ...
- 获取汉字的拼音首字母--pinyin
var pinyin = (function (){ var Pinyin = function (ops){ this.initialize(ops); }, options = { checkPo ...
随机推荐
- Virtual Memory PAGE TABLE STRUCTURE
COMPUTER ORGANIZATION AND ARCHITECTURE DESIGNING FOR PERFORMANCE NINTH EDITION The basic mechanism f ...
- Lazarus解决无法识别中文路径的方法
procedure TForm1.Button1Click(Sender: TObject); var FileN:string; begin if self.OpenDialog1.Execute ...
- 【php学习】图片操作
前两天要对一张图片进行处理,其实很简单,就是在图片上加上字符串,一个图片而已,但是自己如同得了短暂性失忆似的,图片操作的函数一个都想不起来.所以就抽空整理了一下图片操作函数. 图片处理三步走: 创建画 ...
- jbpm node signal
task-node (任务节点) 其性质和node节点一样,在没有task的时候,也都是自动执行,不等待.task-node被归类为一个等待节点,是指在task-node中的task列表中的task没 ...
- [daily][device] linux挂载iphone
头几个月去旅游,亲戚的iphone照了好多照片,空间不足.就备份在了我的电脑上. 那么问题就是如何在linux系统里挂载iphone? 我找到了这篇文档,然而我没看. https://wiki.arc ...
- [dpdk] 读官方文档(3)
续前节, 测试小程序 1. 想编译测试程序首先需要设置两个环境变量,为什么呢,因为测试程序的Makefile里用了... rpm装了打包好的devel包,这个rpm也会自带这两个环境变量.就是说写第三 ...
- QTSingleApplication使用笔记
http://www.cnblogs.com/kevinzhwl/archive/2012/08/27/2658839.html QTSingleApplication,是Qt官方提供的,用于实现只启 ...
- Qt 自定义 滚动条 样式(模仿QQ)
今天是时候把软件中的进度条给美化美化了,最初的想法就是仿照QQ. 先前的进度条是这样,默认的总是很难受欢迎的:美化之后的是这样,怎么样?稍微好看一点点了吧,最后告诉你实现这个简单的效果在Qt只需要加几 ...
- Window上装PHP开发环境 (XAMPP)
原作者:http://www.cnblogs.com/martin1009/archive/2011/11/11/2245794.html 1. 从www.apachefriends.org 上下载X ...
- 【上手centos】二、C/C++的编译与运行
尝试了一下运行C/C++程序,觉得最好还是记下来吧,毕竟也算是从不知到已知呢么. 我用sublime写了2个程序,test.c和test.cpp,分别是C程序和C++程序 step1:编译: #gcc ...