🍇

Swift で BudouX を使ってアラートの改行位置を整える

2021/12/21に公開

BudouX.swift を作りました

Google の BudouX を Swift に移植しました。

BudouX とは?

BudouX をみていただくと分かるとおり、日本語の改行位置を日本語として自然な位置で改行されるようにするツールです。機械学習ベースで分かち書きを行います。スタンドアロンで動作し学習データも15KB程度で軽量なのが特徴です。本家 BudouX は主に Web 開発向けの機能を有しています。HTML を生成したり、Web Component としても動作するようになっています。このあたりは以下のアーティクルを参照いただくと良いかと思います。

なぜ Swift に移植したのか?

僕は普段 iOS アプリ開発をしています。これまでの開発経験の中で度々以下のような経験をしてきました。

👨🏻: 「エラー時にはこの文言をアラートで表示してください」
👨‍💻: (お安いご用で)
👨‍💻: 「できました!こんな感じになります。」
👨🏻: 「🤔... 文言は正しいけど、なんか見た目が気持ち悪い」
👨🏻: 「ここに改行いれておいて」
👨‍💻: (.... \n を文字列中に入れて対応)

UILabel のようなコンポーネントであれば、lineBreakMode を設定して緩和することができるのですが、UIAlertController ではそのような指定はできません。よってこのようなハードコーディングによって改行文字を入れたりしていました。固定文言であればまだこのような対応ができますがサーバから提供される文言の場合はこのような対応もできず

👨‍💻: 「アラートの仕様です」

と逃げることがあります。

BudouX の存在を初めて知ったとき、「(HTML での対応と)同じように改行を避けるような文字を動的に差し込めばいけるのでは?」と思いました。

そこでひとまず iOS アプリ開発で扱う Swift の String で改行位置をある程度調整できるようにしたのがこの BudouX.swift です。

どう実現したのか?

本家 BudouX の HTML 向けの対応は、分かち書きによって分割された文節のつなぎ目に <wbr> タグを挿入することで、レンダリングエンジン側に「ここは改行しても良いところだよ」と伝えることで実現しています。

Swift の String の描画で同様のことを行うために Unicode の以下の文字を使っています。

  • U+2060 (word joiner)
  • U+200B (zero width space)

どちらも普通にみている分には「見えない空白文字」ですが、特別な意味のある文字です。U+2060 (word joiner) は名前の通り単語を繋ぐ役割を持ちます。幅はゼロの文字のため見た目には影響を与えません。改行を避ける特徴があります。U+200B (zero width space) は、その名の通り幅がゼロのスペースですが、改行してもよい特性を持ちます。

本家の HTML 対応と違って、なぜ特殊な意味を持つ文字を2つ挿入しているかは実験結果に基づきます。

BudouX と同様に分かち書きされた文節を U+200B (zero width space) で連結しただけの文字列では、ほぼ何も手を加えていない文字列と同じ改行位置で折り返されてしまいました。
文節内の文字と文字の間に U+2060 (word joiner) を入れるとその文節内では改行はされませんでした。
この事から、iOS の日本語の文字列描画においては以下のように言えると考えました。

  • U+200B (zero width space) と「ただの文字間」に改行処理の比重は変わらない
  • U+2060 (word joiner) で結びつけられた日本語文字の間では改行は避けてくれる

そこで、BudouX.swift では以下のような実装になっています。

  • 分かち書きで分割された文節同士は U+200B (zero width space) で改行されやすく
  • 文節内の各文字間は U+2060 (word joiner) で結びつきを強くし改行されにくくする

移植について

僕自身、Python は分かりませんが、少しだけ JavaScript と TypeScript は読めたので TypeScript 実装をみながら写経するようにして移植しました。言語による挙動差異がどのくらい出るのか不安でしたが、本家はテストがちゃんと書かれていたのでテストをまず写経してからオールグリーンになるように内部実装を進める TDD 風のアプローチで進めました。

今後の予定

現在は、TypeScript で書かれていたコードを Swift に写経のように書き換えることと、StringU+2060 (word joiner) と U+200B (zero width space) を挿入して改行位置を調整できるようにすることに注力しました。以下のような部分を改善していきたいです。

最後に

リポジトリにはサンプルプロジェクトや CLI ツールのコードも含んであります。興味のある方は軽く触ってみてください。

Discussion