引言

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 = 0;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 = 0; int flag = 0;while(*line){   if(*line == '\n'){break;}if(*line == ','){   flag = 1;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 = 0,fromLen = strlen(from),flag = 0;char *tmp = NULL,*strTmp = str;while(tmp = strstr(str, from)){   pos = tmp - str;strncat(ret, str, pos);strcat(ret, to);str = tmp + fromLen;flag = 1;if(is_name)break;}   strcat(ret, str);if(1 == flag){memcpy(strTmp, ret, strlen(ret));strTmp[strlen(ret)] = '\0';}
}

使用

只通过一个函数和标志位来实现,使用起来也是很方便的:
使用的时候可以参考github中的README.md,里面有详细的编译配置细节。

例子
print_r(chinese_to_pinyin("彪悍的人生不需要解释!"));

输出内容,带音标、带标点(标点和拼音挤在一起)

Array
([0] => biāo[1] => hàn[2] => de[3] => rén[4] => shēng[5] => bù[6] => xū[7] => yào[8] => jiě[9] => shì!
)
print_r(chinese_to_pinyin("彪悍的人生不需要解释!", PINYIN_NONE|PINYIN_FORMAT_EN));

输出结果,不带音标,标点符号单独开了:

Array
([0] => biao[1] => han[2] => de[3] => ren[4] => sheng[5] => bu[6] => xu[7] => yao[8] => jie[9] => shi[10] => !
)
print_r(chinese_to_pinyin("燕睿涛"));
print_r(chinese_to_pinyin("燕睿涛", PINYIN_ISNAME));
print_r(chinese_to_pinyin("罗永浩", PINYIN_ISNAME));

输出内容,可以看出PINYIN_ISNAME这个标志位还是很有用的,

rray
([0] => yàn[1] => ruì[2] => tāo
)
Array
([0] => yān[1] => ruì[2] => tāo
)
Array
([0] => luō[1] => yǒng[2] => hào
)

初次之外,还有些关于标志位的使用规律:

PINYIN_NONE、PINYIN_UNICODE两个是对立的,使用前者没有音调,使用后者有音调,默认是前者。

PINYIN_TRIM、PINYIN_FORMAT_EN、PINYIN_FORMAT_CH是对立的,第一个清除所有标点、第二个
使用英文标点,第三个使用中文标点

PINYIN_ISNAME 如果设置了这个标志位,会使用姓氏的规则去解析读音。

总结

这是第二个PHP扩展了,这次写起来跟1年前相比容易了许多,错误也比较少了,继续努力吧~

不要停止学习的脚步,提高自身核心竞争力。

这是github地址:pinyin,欢迎大家点赞、fork、
pull-request或者提建议。

转载于:https://www.cnblogs.com/iforever/p/5543643.html

【汉字】转【pīnyīn】相关推荐

  1. 使用python输出所有汉字的拼音hàn-zì-pīn-yīn

    想在文档中自动把汉字的拼音标注上去,可是很难,用excel或者word来辅助,操作也不方便. 万能的python,加上大神写的拼音工具插件xpinyin,几行代码,就可以把所有汉字的拼音输出!极为强悍 ...

  2. 成语json_推荐一份中文数据,来试试汉字、词语、成语、歇后语在线检索

    前段时间给公众号新增了一个成语接龙功能:AINLP公众号对话接口新增成语接龙,这个里面提到的项目用到了一份成语数据,包含了2万多条成语数据和释义.不过这个数据之外,推荐一个更棒的Github项目: p ...

  3. 利用python实现汉字转拼音的2种方法

    python实现汉字转拼音的2种方法 在浏览博客时,偶然看到了用python将汉字转为拼音的第三方包,但是在实现的过程中发现一些参数已经更新,现在将两种方法记录一下. xpinyin 在一些博客中看到 ...

  4. python把汉字变成拼音英文_利用python将表格中的汉字转化为拼音

    GB18030的字符集标准 http://zbgb5.com/2/StandardDetail479488.htm 缺少包时用pip install 进行安装,例如: pip install xlsx ...

  5. java 对汉字(中文)的汉语拼音(发音)进行排序工具类(代码实现)

    package cn.htd.common.util;import java.io.UnsupportedEncodingException; import java.util.HashMap; im ...

  6. js 根据汉字拼音首字母进行排序

    我们需要一个开源的汉字库,也就是码表.这个库就可以.git库 不想去git下载直接拉到最底下有js文件,直接复制就行. 然后页面引入 import china from '@/utils/china' ...

  7. 【Python】使用python实现汉字转拼音(2018.12更新)

    在浏览博客时,偶然看到了用python将汉字转为拼音的第三方包,但是在实现的过程中发现一些参数已经更新,现在将两种方法记录一下. xpinyin 在一些博客中看到,如果要转化成带音节的拼音,需要传递参 ...

  8. system.out 汉字乱码

    使用sts时,文件编码都设置成了UTF-8,使用system.out.println输出汉字时,出现乱码. 解决方案: run>run configurations>common>e ...

  9. 汉字转换成html,汉字与16进制、汉字与Html转义符的转换

    汉字与16进制.汉字与Html转义符的转换 package test; import java.io.UnsupportedEncodingException; import java.net.URL ...

  10. Java pinyin4j 汉字转拼音包括——多音字

    Java汉字转拼音(包括多音字) 有个需求需要把汉字转拼音,我的小伙伴推荐用Unicode官方的包:下载有些慢. 实际中用了Java工具包:pinyin4j解决 可以转汉字,多音字,多音字的地方要求不 ...

最新文章

  1. CVPR 2018 | 腾讯AI Lab入选21篇论文详解
  2. 高可用、可扩展、稳定和安全的消息队列ActiveMQ特点分析
  3. php jq ajax 4个下拉框联动案列,Ajax与Jquery结合数据库做出实现下拉框的二级联动...
  4. 二、Windows基础数据类型
  5. debian清除无用的库文件(清理系统,洁癖专用)
  6. 全球及中国液氦低温恒温器行业竞争调查分析及前景预测报告2021-2027年版
  7. 计算机网络之应用层:2、DNS域名解析系统
  8. SQLite 3.31.0 发布,世界上使用量最大的数据库引擎
  9. 云南科软信息科技有限公司
  10. centos6.5lamp环境搭建
  11. 项目管理文档_项目管理和团队协同的轻量级工具——PMS,来了
  12. c4d阿诺德渲染器支持a卡吗_请问C4D的OC渲染器支持的显卡是越好越快吗?
  13. 2017计算机应用基础实践,计算机应用基础试题及答案
  14. DELL EMC Isilon配额Quota
  15. MATLAB求解一元二次方程
  16. win7 64 旗舰版虚拟GPU-VMware下+vs2013安装caffe+matlab+python
  17. 深信服php面经,深信服面经
  18. 抗扰度试验--EMS--电压暂降、短时中断--DIP
  19. java实现上传文件夹
  20. iOS开发--AVFoundation进行视频合成, 导出结果旋转90度问题

热门文章

  1. Latex输出大小写罗马数字
  2. 帝国cms 首页php,帝国CMS新增加专题页面
  3. MAC读取NTFS移动硬盘方法
  4. CentOS 官网下载 iso 镜像
  5. 什么是CRM客户管理系统?
  6. 如何通过个人博客赚钱,走上财务自由?
  7. 关于微信小程序认证问题
  8. python中oserror winerror_python – OSError:[WinError87]参数不正确
  9. 分体式水晶头_六类水晶头的接线方法(分体式安装图解)
  10. JS变量特点及分号用法