引言

github地址:aizuyan/pinyin

无意中看到了overtrue/pinyin这个项目,感觉很有意思,

这个项目做了这么一件事情:

将汉字转化为拼音

刚看到这里是不是觉得没什么难度,没什么意思?您不妨接着往下看。要是只是将汉字转为拼音好像

很容易就实现了,但是要是给转换之后的汉字带上音调呢,这样难度就很大了,因为汉字博大精深,

其中一方面就表现在多音字,同样一个字在不同的语句场景下,音调是不一样的。看到这里你在考

虑下如何处理?

这里我还是很佩服安正超(要是不了解他,不妨点进去看看,他

有好几个开源项目都非常棒)这位大神的,他的思路让我眼前一亮:

替换的时候首先将常用的词组替换了,比如短语、成语、常用的词语,这些词语替换的时候按照常

用程度由高到低排序。

接着对剩余的未被替换的汉字进行替换,这里直接按照所有汉字和拼音的映射,没有特定顺序。

如果是姓名,首先对姓氏进行一遍特定替换,姓氏的声调可能和常用的不一致。

除了项目的想法很棒之外,还有一个大难题要解决,就是收集词语,姓氏等,这里我直接使用了安正 超的项目中的数据,再次也该写下安前辈

我的这个项目可以说是很大程度上是安前辈overtrue/pinyin项目的另一个版本。

设计

这个项目中会用到一个数据结构,单链表,用来存储拼音、汉字对应关系的数据,一开始想着使用Bu cket数据结构,后来觉得,这个数据结构体里面冗余的信息太多了,也不是很符合我预想的数据结构,

so,最后使用了下面的数据结构:

typedef struct mylist {
char *key; //词语、成语或者单个汉字
char *val; //对应的拼音,拼音前面都有一个制表符`\t`
struct mylist *next; //指向下一个汉字拼音结构体
} MyList;

除此之外,我还考虑了性能问题,安前辈php版本的有个固有的缺陷,每次请求都要去加载一遍数据文

件,大概有600700kb左右,转换为数组,元素个数为4000050000个左右,每次请求都会分配、释放这部分内

存。而且这个过程会有大量的计算过程(查找、替换),这也是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或者提建议。

【汉字】转【pīnyīn】的更多相关文章

  1. ADF_Data Binding系列1_使用Bean Data Control

    2015-02-16 Created By BaoXinjian

  2. 结巴分词3--基于汉字成词能力的HMM模型识别未登录词

    作者:zhbzz2007 出处:http://www.cnblogs.com/zhbzz2007 欢迎转载,也请保留这段声明.谢谢! 1 算法简介 在 结巴分词2--基于前缀词典及动态规划实现分词 博 ...

  3. .net汉字转字母

    目前手上有一个需要实现:将用户输入的姓名转换成汉语拼音. 使用枚举,既麻烦又易出错,发现有一个微软拼音转换工具类ChnCharInfo.dll,在此记录下: 首先需要引入此dll, 链接: http: ...

  4. STemwin汉字显示

    硬件环境: STM32F429,电容屏800X480 5点触控RGB屏幕 ,SPI flash: 软件环境: UCOSIII,STemwin: 汉字显示方法: 1.在SPIflash中装在字库XBF_ ...

  5. 【转载】C#怎么判断字符是不是汉字

    支持并尊重原创!原文地址:http://jingyan.baidu.com/article/2c8c281deb79ed0008252af1.html 判断一个字符是不是汉字通常有三种方法,第1种用 ...

  6. iOS 汉字的拼音

    获取汉字的拼音 #import <Foundation/Foundation.h> @interface NSString (Utils) /** * 汉字的拼音 * * @return ...

  7. Oracle汉字转拼音package

    --函数GetHzFullPY(string)用于获取汉字字符串的拼音 --select GetHzFullPY('中华人民共和国') from dual; --返回:ZhongHuaRenMinGo ...

  8. Linux C语言解析.bmp格式图片并显示汉字

    bmp.h 文件 #ifndef __BMP_H__ #define __BMP_H__ #include <unistd.h> #include <stdio.h> #inc ...

  9. [python]获取网页中内容为汉字的字符串的判断

    实际上是这样,将获取到网页中表单内容与汉字字符串作比较,即: a = request.POST['a'] if a == '博客园': print 'ok' else: print 'false' a ...

随机推荐

  1. Atitit Atitit.软件兼容性原理----------API兼容 Qa7

    Atitit Atitit.软件兼容性原理----------API兼容 Qa7 1. 兼容性的重要性与反面教材1 2. 提升兼容性的原则2 2.1. What 与how 分离2 2.2. 老人老办法 ...

  2. css3+jquery制作3d旋转相册

    首先来看一下今天的炫酷效果: 首先分析一下这张图片: 1.每张图片都有倒影 2.这11张图片呈圆形均匀排列 3.可旋转,上下移动(当然这是效果做出来以后,图片是分析不出来的) 那下面就开始吧. 一.准 ...

  3. CSS类似微软中国首页的竖向选项卡

    效果体验:http://hovertree.com/texiao/css/24/ 源码下载:http://hovertree.com/h/bjaf/hardklps.htm 代码如下: <!DO ...

  4. H5 meta小结

    <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1, ...

  5. asp.net web api 的版本升级到 2.2的记录

    asp.net web api 的版本 升级到 2.2的记录 asp.net web api 2.2相比1.0提升了不少 而且其中最重要的就是有了在线文档的自动字段注释的功能 再也不用写详细的字段说明 ...

  6. 基于Python+Django的Kubernetes集群管理平台

    ➠更多技术干货请戳:听云博客 时至今日,接触kubernetes也有一段时间了,而我们的大部分业务也已经稳定地运行在不同规模的kubernetes集群上,不得不说,无论是从应用部署.迭代,还是从资源调 ...

  7. Linux下安装 Posgresql 并设置基本参数

    在Linux下安装Postgresql有二进制格式安装和源码安装两种安装方式,这里用的是二进制格式安装.各个版本的Linux都内置了Postgresql,所以可直接通过命令行安装便可.本文用的是Cen ...

  8. QPalette的用法

    1.QPalette的概念 调色板类QPallete提供了颜色角色(color roles)概念,是指当前GUI界面中颜色的职责,通过枚举变量QPalette::ColorRole来定义, 比较常用的 ...

  9. 记录 git 常用的操作命令总结

    记录 git 常用的操作命令总结 2016-12-15 16:44:04 作为一名开发者,熟悉使用 git 代码管理工具是一项必备的基本技能.git 相较 SVN 而言,其优点不言而喻.git 的功能 ...

  10. mongodb管理篇

    一.  管理工具集 数据迁移 Mongoexport:用于针对colletions的数据导出,或者打开单个字段. Mongodbimport:与只对应,这个表示在导出的基础上导入. 数据库的备份恢复 ...