当前位置: 首页 > 后端技术 > PHP

PHP中文工具包ChineseUtilv2.0发布,引入FFI提高性能节省内存

时间:2023-03-29 14:17:54 PHP

ChineseUtil是一款PHP中文工具包,支持汉字转拼音、拼音分词、简繁转换、数字转换、金额转换转换。由于汉语博大精深,注音文字众多,简体字与繁体字的对应关系也很多。而这个类库返回的所有结果都是包含所有组合的数组。本类库词典数据共收录汉字73925个,其中:简体字3955个,繁体字1761个,其他汉字68209个。Github:https://github.com/Yurunsoft/...更新日志v2.0.0(2020-08-17)支持FFI,SwooleFFI重构拼音分词算法拼音分词支持可选数组或字符串数??组结果随本次更新,FFI支持启动。FFI动态库C++代码:https://github.com/Yurunsoft/...项目缘起2020年7月,开始学习C++,那到底该学什么。想反哺PHP生态,那就把我之前开发的ChineseUtil性能提升一下吧。于是折腾了一个多月研究,一开始是在C++项目的配置上折腾。然后开发了FFIC函数,效果不是很理想。性能上什至不如PHP算法,因为FFI转换的是字符串数组,甚至是二维数组,效率太低太繁琐,而且有内存泄漏的风险。经过研究,我尝试了目前的解决方案,即调用zend_register_functions()函数来动态创建PHP函数。类似于PHP扩展的开发,但通过FFI创建。所以问题是,为什么不把它做成一个PHP扩展呢?我的初衷是让ChineseUtil库开箱即用,不用编译,不用启用扩展,比较麻烦。PHPdl()函数也可以动态加载扩展,但这在许多环境中是禁用的。然后FFI动态创建PHP函数成为最佳解决方案(也许)。Mode性能模式(Memory)以SQLite为数据载体,一次性加载所有数据到变量中,内存占用高(80+MB),性能最好。适合运行CLI任务。需要PDO和PDO_SQLITE扩展支持。普通模式(SQLite)以SQLite为数据载体,每次查询均通过SQL查询,内存占用低(100-200KB),性能中等。适用于大多数场景。需要PDO和PDO_SQLITE扩展支持。兼容模式(JSON)使用简化的JSON数据作为数据载体,一次将所有数据加载到变量中,占用大量内存(30+MB),性能较差。内存使用以实际情况为准。根据版本、扩展等环境,占用的内存容量不同。以上数值基于我的电脑,仅供参考。适用于不能使用PDO的场景。由于数据的简化,部分拼音结果需要代码计算处理,性能较差。FFI模式(FFI)要求PHP>=7.4并启用FFI扩展,代码全部由C++开发,性能和内存占用优于PHP实现。FFI动态库C++代码:https://github.com/Yurunsoft/...SwooleFFI模式(SwooleFFI)要求PHP>=7.4,并启用FFI和Swoole扩展。代码全部由C++开发,其性能和内存占用都比PHP实现的更好。不会阻塞PHP代码所在的线程。默认先使用普通模式,如果环境不支持PDO就会使用兼容模式。您可以在执行任何初始化或转换处理之前设置要使用的模式。//设置为性能模式Chinese::setMode('Memory');//设置为通用模式Chinese::setMode('SQLite');//设置为兼容模式Chinese::setMode('JSON');//设置为FFI模式Chinese::setMode('FFI');//设置为SwooleFFI模式Chinese::setMode('SwooleFFI');不管是哪种模式,拼音分词需要的数据都是从JSON数据中加载的。Composerinstallcomposer直接requireyurunsoft/chinese-utilComposer工程配置引入"require":{"yurunsoft/chinese-util":"~1.1"}函数汉字转拼音use\Yurun\Util\Chinese;use\Yurun\Util\Chinese\Pinyin;$string='恭喜发财!123';echo$string,PHP_EOL;echo'全拼:',PHP_EOL;var_dump(Chinese::toPinyin($string,Pinyin::CONVERT_MODE_PINYIN));echo'首字母:',PHP_EOL;var_dump(Chinese::toPinyin($string,Pinyin::CONVERT_MODE_PINYIN_FIRST));echo'发音:',PHP_EOL;var_dump(Chinese::toPinyin($string,Pinyin::CONVERT_MODE_PINYIN_SOUND));echo'发音编号:',PHP_EOL;var_dump(Chinese::toPinyin($string,拼音::CONVERT_MODE_PINYIN_SOUND_NUMBER));echo'可选返回格式+文本格式返回+自定义分隔符:',PHP_EOL;var_dump(Chinese::toPinyin($string,Pinyin::CONVERT_MODE_PINYIN|Pinyin::CONVERT_MODE_PINYIN_SOUND_NUMBER,''));echo'所有结果:',PHP_EOL;var_dump(Chinese::toPinyin($string));echo'不拆分非拼音字符:',PHP_EOL;var_dump(Chinese::toPinyin($string,Pinyin::CONVERT_MODE_PINYIN,'',false));//结果太长,请自行运行代码检查拼音分割结果是否为字符串:use\Yurun\Util\Chinese;$string2='xiganggang';echo'"',$string2,'":'的分词结果,PHP_EOL;var_dump(Chinese::splitPinyin($string2));输出结果:"xianggang"的分词结果:array(2){[0]=>string(11)"xianggang"[1]=>string(12)"xianggang"}结果是一个数组:use\Yurun\Util\Chinese;$string2='xianggang';echo'"',$string2,'",PHP_EOL的分词结果;var_dump(Chinese::splitPinyinArray($string2));输出结果:“xianggang”的分词结果:array(2){[0]=>array(2){[0]=>string(5)"xiang"[1]=>string(4)"gang"}[1]=>array(3){[0]=>string(2)"xi"[1]=>string(3)"ang"[2]=>string(4)"gang"}}简化而繁体转换使用\Yurun\Util\Chinese;$string3='中华人民共和国!愿你幸福快乐!';echo'"',$string3,'"的简体转换:',PHP_EOL;var_dump(Chinese::toSimplified($string3));echo'"',$string3,'"的繁体转换,PHP_EOL;var_dump(Chinese::toTraditional($string3));输出结果:“中华人民共和国!恭喜发财!”的简化转换:array(1){[0]=>string(39)"中华人民共和国!恭喜发财!"}"中华人民共和国中国!恭喜发财!”繁体转换:array(1){[0]=>string(39)"中华人民共和国!恭喜发财!"}numberWord转换使用Yurun\Util\Chinese\Number;functiontest($number){$chinese=Number::toChinese($number,['tenMin'=>true,//"十二"=>"十二"]);$afterNumber=Number::toNumber($chinese);echo$number,'=>',$chinese,'=>',$afterNumber,'=>',0===bccomp($number,$afterNumber,20)?'真':'假',PHP_EOL;}测试(1.234);测试(-1234567890.666);测试(pi());输出:1.234=>1.234=>1.234=>true-1234567890.666=>negative1.234567890.666=>-1234567890.666=>true3.1415926535898=>3.1415926535898=>3.141592890.666=>true3.1415926535898=>3.1415926535898=>3.141592890.666=>true3.1415926535898=>3.1415926535898=>3.141592890.653functiontest($number){$chinese=Money::toChinese($number,['tenMin'=>true,//"一十二"=>"十二"]);$afterMoney=Money::toNumber($chinese);echo$number,'=>',$chinese,'=>',$afterMoney,'=>',0===bccomp($number,$afterMoney)?'真':'假',PHP_EOL;}测试(1.234);测试(-1234567890.666);输出结果:输出结果:1.234=>一轮二角三点4%=>1.234=>true-1234567890.666=>负一亿二千三千四十五六万七八百九十圆土地角地分地分=>-1234567890.666=>真