Google製の改行位置決定アルゴリズムBudouxをLuaに移植した

by
カテゴリ:

メリークリスマス! atusyサンタからのクリスマスプレゼントはatusy/budoux.lua!

Budouxは文字列の改行を、人間にとって読みやすい位置で行うためのアルゴリズム。 Google製で、日本語や中国語、タイ語に対応し、PythonやJavaScript、Javaの実装が公式提供されている。

deno eval \
  'import { loadDefaultJapaneseParser } from "npm:budoux"; 
   console.log(loadDefaultJapaneseParser().parse("今日は天気です。"));'
# [ "今日は", "天気です。" ]

今回はatusy/budoux.luaとして、Luaに移植した(とりあえず日本語だけ)。

local budoux = require("budoux")
local parser = budoux.load_japanese_model()
parser.parse('今日は天気です。')
-- { "今日は", "天気です。" }

有名なあなたとJAVA,今すぐダウンロードもうまく分割できる。

require("budoux").load_japanese_model().parse("あなたとJAVA,今すぐダウンロード")
-- { "あなたと", "JAVA,", "今すぐ", "ダウンロード" }

もう少し長文で「我輩は猫である」の冒頭を分割するととこんな感じ。

require("budoux").load_japanese_model().parse(
  "吾輩は猫である。名前はまだ無い。どこで生れたかとんと見当がつかぬ。" ..
  "何でも薄暗いじめじめした所でニャーニャー泣いていた事だけは記憶している。"
)
--[[
{ 
  "吾輩は", "猫である。", "名前は", "まだ", "無い。", "どこで", "生れたかとんと", "見当が", "つかぬ。",
  "何でも", "薄暗いじめじめした所で", "ニャーニャー泣いていた", "事だけは", "記憶している。"
}
]] 

Budouxを使うと、Bionic readingの日本語版を軽量に実装できないかなと思っている。文節ごとに、先頭数文字を太字にして目が滑りにくくするイメージ。先の「我輩は猫である」の例だと以下の通り。

吾輩である。名前まだい。どこれたかとんと見当がつかぬ。でも薄暗いじめじめした所でニャーニャー泣いていただけは記憶している。

できればNeovimで実現したくて今回、Luaに移植した。

一方で、Neovim以外でも使えるように工夫した。だからbudoux.nvimではなくbudoux.luaを名乗っている。

主に2点の工夫が必要だった。

LuaはUnicode文字をネイティブに扱えず、日本語を文字単位で文を分割することが難しい。そこで、lpegというパターンマッチングライブラリを使って分割した。

(lpeg.Ct(lpeg.C(lpeg.utfR(0, 0x10ffff)) ^ 0)):match("日本語")
-- { "日", "本", "語" }

ちなみにVim/Neovimであればsplit('日本語', '\zs')のようにできる。

分割の判断基準となるデータは公式にはJSONで提供されているが、LuaはJSONパーサーを標準で持っていない。そこで、文字列置換でLuaテーブル化して、簡単に読み込めるようにした。

冬休みのうちにbionic readingを実装できるといいなあ。

ENJOY!