PHP 中文工具包 ChineseUtil v2.0 發佈,引入 FFI 提高性能節省內存

ChineseUtil 是 PHP 中文工具包,支持漢字轉拼音、拼音分詞、簡繁互轉、數字轉換、金額數字轉換。php

因爲中文的博大精深,字有多音字,簡體字和繁體字也有多種對應。而且本類庫返回的全部結果,均爲包含全部組合的數組。git

本類庫字典數據總共收錄 73925 個漢字,包括:3955 個簡體字,1761 個繁體字,68209 個其它漢字。github

Github:https://github.com/Yurunsoft/...算法

更新日誌

v2.0.0 (2020-08-17)shell

  • 支持 FFI、Swoole FFI
  • 重構拼音分詞算法
  • 拼音分詞支持可選獲取數組或字符串數組的結果集

本次更新,重磅推出了 FFI 支持。FFI 動態庫 C++ 代碼:https://github.com/Yurunsoft/...數組

項目起源

2020 年 7 月份開始想研究 C++,那麼研究點什麼好呢。想着反哺一下 PHP 生態,那麼就爲我以前開發的 ChineseUtil 提高一下性能吧。composer

因而有了一個多月的折騰研究,起初是折騰 C++ 項目的配置。函數

而後是開發了 FFI C 函數,效果不是很理想。性能甚至都不如 PHP 算法,緣由是 FFI 轉換字符串數組,甚至是二維數組,效率實在是過低而且麻煩,有內存泄漏風險。工具

通過一番研究,嘗試了一下目前的方案,也就是調用 zend_register_functions() 函數來動態建立 PHP 函數。性能

相似於 PHP 擴展的開發,可是是經過 FFI 來建立的。

那麼問題來了,爲啥不直接作成 PHP 擴展?

個人本意呢,是讓 ChineseUtil 這個庫能夠開箱即用,不須要編譯、啓用擴展啥的,麻煩。

PHP dl() 函數也能夠動態加載擴展,可是不少環境中是被禁用的。

那麼 FFI 來動態建立 PHP 函數,就成了最佳方案(也許)。

模式

性能模式 (Memory)

使用 SQLite 做爲數據載體,一次性加載全部數據到變量,內存佔用高(80+ MB),性能最佳。

適合用於運行 Cli 任務。

須要 PDO 和 PDO_SQLITE 擴展支持。

通用模式 (SQLite)

使用 SQLite 做爲數據載體,每次查詢都經過 SQL 查詢,內存佔用低(100-200 KB),性能中等。

適合用於大部分場景。

須要 PDO 和 PDO_SQLITE 擴展支持。

兼容模式 (JSON)

使用精簡過的 JSON 數據做爲數據載體,一次性加載全部數據到變量,內存佔用中(30+ MB),性能差。

內存佔用量以實際爲準,根據版本、擴展等環境的不一樣,佔用的內存容量不同,上述值爲我電腦上的狀況,僅供參考。

適合沒法使用 PDO 的場景。

因爲精簡了數據,一些拼音結果須要通過代碼計算處理才能夠得出,因此性能較差。

FFI 模式 (FFI)

須要 PHP >= 7.4 而且啓用 FFI 擴展,代碼所有由 C++ 開發,性能和內存佔用都比 PHP 實現的要好。

FFI 動態庫 C++ 代碼: https://github.com/Yurunsoft/...

Swoole FFI 模式 (SwooleFFI)

須要 PHP >= 7.4 而且啓用 FFI、Swoole 擴展,代碼所有由 C++ 開發,性能和內存佔用都比 PHP 實現的要好。

不會阻塞 PHP 代碼所在線程。


默認狀況下,優先使用通用模式,若是環境不支持 PDO 將採用兼容模式。

你能夠在未執行任何初始化或者轉換處理以前,設置使用何種模式運行。

// 設爲性能模式
Chinese::setMode('Memory');
// 設爲通用模式
Chinese::setMode('SQLite');
// 設爲兼容模式
Chinese::setMode('JSON');
// 設爲 FFI 模式
Chinese::setMode('FFI');
// 設爲Swoole FFI 模式
Chinese::setMode('SwooleFFI');

不管何種模式,拼音分詞所需數據老是從 JSON 數據中加載。

使用說明

Composer 直接安裝

composer require yurunsoft/chinese-util

Composer 項目配置引入

"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, Pinyin::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 = 'xianggang';
echo '"', $string2, '"的分詞結果:', PHP_EOL;
var_dump(Chinese::splitPinyin($string2));

輸出結果:

"xianggang"的分詞結果:
array(2) {
  [0]=>
  string(11) "xiang gang"
  [1]=>
  string(12) "xi ang gang"
}

結果是數組:

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"
  }
}

簡繁互轉

use \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) "中華人民共和國!恭喜發財!"
}

數字轉換

use Yurun\Util\Chinese\Number;
function test($number)
{
    $chinese = Number::toChinese($number, [
        'tenMin'    =>  true, // 「一十二」 => 「十二」
    ]);
    $afterNumber = Number::toNumber($chinese);
    echo $number, '=>', $chinese, '=>', $afterNumber, '=>', 0 === bccomp($number, $afterNumber, 20) ? 'true' : 'false', PHP_EOL;
}

test(1.234);
test(-1234567890.666);
test(pi());

輸出結果:

1.234=>一點二三四=>1.234=>true
-1234567890.666=>負十二億三千四百五十六萬七千八百九十點六六六=>-1234567890.666=>true
3.1415926535898=>三點一四一五九二六五三五八九八=>3.1415926535898=>true

金額數字轉換

use Yurun\Util\Chinese\Money;
function test($number)
{
    $chinese = Money::toChinese($number, [
        'tenMin'    =>  true, // 「一十二」 => 「十二」
    ]);
    $afterMoney = Money::toNumber($chinese);
    echo $number, '=>', $chinese, '=>', $afterMoney, '=>', 0 === bccomp($number, $afterMoney) ? 'true' : 'false', PHP_EOL;
}

test(1.234);
test(-1234567890.666);

輸出結果:

輸出結果:
1.234=>壹圓貳角叄分肆釐=>1.234=>true
-1234567890.666=>負壹拾貳億叄仟肆佰伍拾陸萬柒仟捌佰玖拾圓陸角陸分陸釐=>-1234567890.666=>true
相關文章
相關標籤/搜索