読みやすい改行のための軽量な分かち書き器をPHPで
BudouXという汎用の日本語分かち書きライブラリがあります。
以前これのJava版実装をPHPに移植したことがありました。
アルゴリズムがとても簡単なのでPHPでも簡単に動かせるので便利です。
ところで、先述のGoogle社のブログにはこんなことが書いてあります。
今後の展開
現在 BudouX は ICU (International Components for Unicode) の一部になっており、ウェブに限らずさまざまなプラットフォームで利用され始めています。
おや。ICUというのは、PHPでいえばIntl
モジュールのことです。PHPでもBudouXが使えるのではないのでしょうか!
ICUにBudouXがやってきた!
改めて、ICUとはユニコードコンソーシアムが開発しているUnicodeおよび国際化と地域化のためのライブラリです。
2024年12月時点での最新版は2024年10月24日のICU 76で、BudouXがマージされたのは2023年4月13日にリリースされたICU 73です。
2023-04-13: ICU 73 updates to CLDR 43 locale data with various additions and corrections. ICU 73 improves Japanese and Korean short-text line breaking, reduces C++ memory use in date formatting, and promotes the Java person name formatter from tech preview to draft. For details, see Downloading ICU > ICU 73.
Line breaking with Japanese phrase-based breaking is now using the BudouX machine learning implementation for better quality. (ICU-22100, see ICU 71 ICU-21699 for context)
使用条件を満たしているか調べる
WebサーバまたはコマンドラインからPHPを実行して、INTL_ICU_VERSION
を見てみましょう。
以下はmacOSでHomebrewを使ってインストールしたPHP 8.4.2です。
% php -r 'var_dump([INTL_ICU_VERSION, INTL_ICU_DATA_VERSION]);'
array(2) {
[0]=>
string(4) "76.1"
[1]=>
string(4) "76.1"
}
ばっちりですね!
ところで、一般的なサーバ環境ではICU 73以上を使えるのでしょうか…?
ためしにDebianのlibicu-dev
パッケージを見てみましょう。
実際に手元のDebian 12(Bookworm)でビルドしたPHPで試してみるとこうなります。
% php -r 'var_dump([INTL_ICU_VERSION, INTL_ICU_DATA_VERSION]);'
array(2) {
[0] =>
string(4) "72.1"
[1] =>
string(4) "72.1"
}
残念… ではあるのですが、実際にはフレーズベースの分かち書きはICU 71の時点で取り入れられていて、ICU 73で入ったのは「BudouXを使ったよりよい品質の実装」ので、BudouXと完全互換に同じ分割結果になることにこだわらなければ、使えます。
とても残念なことに、PHPのオンラインサンドボックス環境としてよく使われている3v4l.orgはICU 63がリンクされているので、日本語の分かち書き検証には使えません。また、最近よく使われているブラウザ上のWasmランタイムでPHPを動かせるPHP Playground(php-play.dev)は、そもそもICU(intl)がリンクされていません。
使い方
IntlBreakIterator
クラスを使います。
$iter = IntlBreakIterator::createLineInstance('ja-u-lw-phrase');
$iter->setText('BudouX: 読みやすい改行のための軽量な分かち書き器');
var_dump(iterator_to_array($iter->getPartsIterator()));
// => array(8) {
// [0] =>
// string(8) "BudouX: "
// [1] =>
// string(6) "読み"
// [2] =>
// string(9) "やすい"
// [3] =>
// string(9) "改行の"
// [4] =>
// string(9) "ための"
// [5] =>
// string(9) "軽量な"
// [6] =>
// string(15) "分かち書き"
// [7] =>
// string(3) "器"
// }
IntlBreakIterator::createLineInstance('ja-u-lw-phrase')
というのは呪文です。いやちゃんと意味はあるのですが… いまのところはこういうものだと思ってください。
$iter->getPartsIterator()
はイテレータ、つまり「foreach
できるオブジェクト」を返します。そのままforeach
に渡してもいいですし、よくわからんという人はiterator_to_array()
関数に渡せば配列に変換できます。
Intl vs BudouX for PHP
PHP実装とIntl、どちらを使えばよいのでしょうか…?
ICU 71以上が入っている環境ならICUを使った方がいいんじゃないかと思います。パフォーマンス30〜40倍くらい違うので…
計測コードは以下の通り。
Discussion