🌙

Neovimで日本語を分かち書きできるようにした話

2024/12/02に公開

本記事はVim Advent Calendar 2024の12/2の記事となります。

概要

https://github.com/sirasagi62/tinysegmenter.nvim
 tinysegmenter.nvimはわずか25KBの辞書に依存しない分かち書きソフトウェア、TinySegmenterのLua移植です。
 Neovimで外部のランタイムや巨大な辞書をインストールせずに分かち書きを行えるようになります。また、実装そのものはNeovimに依存しないためLuaが使えるあらゆる環境下に展開できます。

Install & Usage

インストール

-- vim-jetpackを使う場合
Jetpack "sirasagi62/tinysegmenter.nvim"

使い方

local tinysegmenter = require("tinysegmenter")
local parsed_text = tinysegmenter.segment("これは文章です。")
print(table.concat(parsed_text,"|"))
-- これ|は|文章|です|。

TinySegmenterとは?

TinySegmenterはMeCabやSentencePieceでおなじみの自然言語研究者、工藤拓氏によって開発されたわずか25KBのJavaScript製分かち書きソフトウェアです。通常の分かち書きソフトウェアでは単語境界を推定するために100MB程度の辞書を添付する必要があるのですが、TinySegmenterは辞書を内包せずに勾配ブースティングの一種であるAdaBoostで境界を推定することで小容量で高精度な解析を実現しています。その取り回しのよさから、主にJS/TS製の様々なプロジェクトで利用されています。

なぜLuaで書き直したか

TinySegmenter自体はbunsetsu.vimに組み込まれたり、Vim script移植なども存在し、NeovimのみならずVimからも既に利用することができます。しかし、これらのプラグインは実装がdenops依存であったり、Vim scriptによるものであったりします。
 一方、本プラグインは2つのファイルから成るただのLuaスクリプトであるため、通常のNeovimプラグインと同様の手順で利用できます。またNeovim内蔵のLua処理系を用いるためディスク消費量も非常に少ないです。速度もデフォルトのNeovimはLuaJITを採用しているため、本家と同等かそれ以上のパフォーマンスが出ると思います。(要検証)
 加えて、実装がNeovimの内部ライブラリにすら依存していないため、Lua5.1が動く環境であればゲームエンジン/DB/サーバー問わずどこでも動かすことができるようになりました。やろうと思えば、nginxに組み込んで文節区切りサーバーを作ったり、redisで文字列を保存するたびに転置インデックスを更新したりできると思います。

難しかったこと

Luaの文法

Luaの文法にはいくつか癖があります。

  • オブジェクトのキーに非英数字を用いる場合には["キー"]あるいは[[キー]]のように囲む必要がある
  • 文字列同士を..で連結する
  • 配列(厳密にはTableの一形態)のインデックスが1から始まる

などです。普段LuaそのものはNeovimの設定で触れてはいるものの、ここまで深い機能には触れないためエラーを特定するのに少し時間がかかりました。
 ちなみに実装の書き直しは機械による処理ではなく、人力+Neovimの編集機能のゴリ押しです。LuaとJSでは比較的文法が似ているのとNeovim(Vim)のテキスト編集機能が充実しているため案外どうにかなります。

非英数字の扱い

TinySegmenterでは単語境界推定の特徴量として文字の種類を用いており、各文字を「漢数字」「漢字」「ひらがな」「カタカナ」「アルファベット」「数字」の6つに分類しています。元の実装言語であるJavascriptはWeb標準の正規表現で簡単に特定できます。しかし、LuaではそもそもUTF-8に対応したのが5.3以降[1]であり、Neovimに組み込まれているlpegライブラリもUTF-8サポートを含まない[2]ためこれらの文字種の分類を独自に実装する必要があります。今回はuga-rosa氏のLua5.1で5.3相当のUTF-8機能が触れるバックポートライブラリを用いて各文字の種類を推定する機構を実装しました。

まとめ

200行/25KBの超軽量分かち書きソフトウェアTinySegmenterのLua移植を紹介しました。Neovimで手軽に導入できるようになっているので、ぜひ色々なプラグインから使ってみてください!

脚注
  1. Neovimに含まれるLuaは5.1相当 ↩︎

  2. 最新バージョンのLPEGでは対応しているものの、Neovimには組み込まれていません。 ↩︎

Discussion