引言

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】的更多相关文章

  1. 使用pinyin4j汉字转pinyin

    引入maven依赖<dependencies> <dependency> <groupId>com.belerweb</groupId> <art ...

  2. 基于SolrCloud的内容搜索和热点推送

    ➠更多技术干货请戳:听云博客 什么是热点 我认为热点有时效性和受众面 用户关注从低到高再到低的内容 .有公共热点和分类热点.例如医辽养老全民关注,科技汽车等只有特定的人群关注. 推送的条件 搜索频次达 ...

  3. solr入门之搜索建议的几种实现方式和最终选取实现思路

    上篇博客中我简单的讲了下solr自身的suggest模块来实现搜索建议.但是今天研究了下在solr自身的suggest中添加进去拼音来智能推荐时不时很方便.在次从网上搜集和整理思考了下该问题的解决. ...

  4. select2 全拼以及首字母

    转自:https://blog.csdn.net/kanhuadeng/article/details/78475317 具体实现方法为: 首先需要在网上下载select2的源码,并引入到项目中,具体 ...

  5. solr入门之pinyin4j源代码改写动态加入扩展词及整合进war项目中

    1.初始化时载入用户定义的字典 package net.sourceforge.pinyin4j; import net.sourceforge.pinyin4j.multipinyin.Trie; ...

  6. 搜索引擎keyword智能提示的一种实现

    问题背景 搜索关键字智能提示是一个搜索应用的标配.主要作用是避免用户输入错误的搜索词,并将用户引导到相应的关键词上,以提升用户搜索体验. 美团CRM系统中存在数以百万计的商家,为了让用户高速查找到目标 ...

  7. [功能帮助类] C#取汉字拼音的首字母PinYin帮助类 (转载)

    点击下载 PinYin.rar 主要功能就是取汉字拼音的首字母,只要你输入一个汉字,或者是多个汉字就会取出相应的道字母,主要是方便查询使用的 /// <summary> /// 编 码 人 ...

  8. 【Python】 汉字转化汉语拼音pinyin

    pinyin pinyin模块是github上一个小项目,在github.com/cleverdeng/pinyin.py上面可以下到源码.衷心感谢那些为这个模块做出贡献的人来方便我们[鞠躬] 安装: ...

  9. 获取汉字的拼音首字母--pinyin

    var pinyin = (function (){ var Pinyin = function (ops){ this.initialize(ops); }, options = { checkPo ...

随机推荐

  1. 如何解决php 生成验证码图片不显示问题

    最近遇到一个问题,就是验证码在别人的电脑上可以显示,但是我自己的电脑上去不能.原因找了好久,哈哈,终于找到了!现在给大家分享一下: 程序: <?php $w = 80; //设置图片宽和高 $h ...

  2. Linux命令echo -e

    在Linux命令中 echo -e 这个参数e是什么意思. echo –e “I will use ‘touch’ command to create 3 files.” 这里参数e的作用是什么 ma ...

  3. java event

    What is an Event? Change in the state of an object is known as event i.e. event describes the change ...

  4. Mysql 只导出数据,不包含表结构

    mysqldump -u${user} -p${passwd} --no-create-info --database ${dbname} --table ${tablename} > ${ta ...

  5. Android性能优化典范(转)

    转载自oschina. 2015年伊始,Google发布了关于Android性能优化典范的专题, 一共16个短视频,每个3-5分钟,帮助开发者创建更快更优秀的Android App.课程专题不仅仅介绍 ...

  6. mysql基本sql语句大全(提升用语篇)

    1.说明:复制表(只复制结构,源表名:a 新表名:b) (Access可用) 法一:select * into b from a where 1<>1(仅用于SQlServer) 法二:s ...

  7. MVC分页控件之二,为IQueryable定义一个扩展方法,直接反回PagedList<T>结果集(转)

    namespace Entity { public interface IPagedList { /// <summary> /// 记录数 /// </summary> in ...

  8. mongo安装、备份与常见命令整理

    http://zlboy888.blog.163.com/blog/static/315357072012919241104/ 1 下载安装包  官方下载地址:http://www.mongodb.o ...

  9. EChars学习-1

    Echarts,编写来自Enterprise Charts,商业级数据图表,是百度的一个开源的数据可视化工具 官网地址:http://echarts.baidu.com/ 一.引入Echarts &l ...

  10. JQuery 可见性过滤选择器

    <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <m ...