自分の専門から離れて見える場所にも、エンジニアリングで手伝えることがある。

そう思い、指定した小学校学年ではまだ習わない漢字を検出するtextlintルール、textlint-rule-ja-grade-kanji を作った。

きっかけは、同人誌の校正について書かれたXの投稿 だった。小学生のキャラクターが書いた文章なら、その学年までに習う漢字だけで書かれているかもキャラクターらしさに関わるという。

その話を読んで気になったのは、特定のキャラクターを再現する方法だけではなかった。正直、キャラクターは関係ない。
小説や合同誌の校正にtextlintを持ち込めば、同人誌などの文化をエンジニアの目線から支援できるのではないか。

その好奇心から手を動かした。

書くことと校閲することは別の仕事

頭の中にあるものを文章として出力できることと、その文章を校閲できることは別だと考えている。

これは文系と理系のような区分の話ではない。書き手が豊かな発想を文章にできても、表記の揺れや規則からの逸脱をすべて自力で見つけられるとは限らない。

校閲の中には、文脈を読み、表現の意図を考えなければ判断できないものがある。
一方で、明確な規則へ落とせるものもある。

後者であれば、エンジニアが仕組みを作って支援できる。

最初の題材にしたのが、学年別漢字だった。常用漢字を検査するtextlintルールはすでにある。学年別漢字を扱うルールも数年前に作られていたが、開発を始めた時点では更新が止まっているように見えた。

ただし、既存ルールを調べ尽くしたうえで新しい実装を選んだわけではない。まず自分で作ってみたいという好奇心が先に立ち、類似パッケージの存在へ詳しく気づいたのは作ったあとだった。

一つの規則だけを検査する

textlint-rule-ja-grade-kanjiは、文部科学省の「学年別漢字配当表」に基づき、指定した学年までに習う漢字だけが文章に使われているかを検査する。

たとえば小学2年生向けの設定で「植物を観察する」と書くと、「植」は3年生、「観」と「察」は4年生で習う漢字として、一文字ずつ報告する。

利用場面として最初に思い浮かべたのは、きっかけになった投稿のように、小学生のキャラクターが読み書きする文章だった。
それだけでなく、小学生向けの教材や案内文を作る人が、対象学年では読めない可能性のある漢字を探す用途にも使える。

学年の指定、固有名詞などに使う漢字の許可、特定部分を検査対象から外す設定は、最初から必要だと考えていた。
実装を進める中では、学年別漢字配当表にない漢字の検出や、珍しい漢字を扱うときに文字の位置がずれる問題をAIから指摘された。

Unicodeでは、文字に割り当てる番号の範囲を「平面 」という単位で分けている。 最初の平面には普段よく使う文字が多く収められており、それより後ろの平面を補助平面と呼ぶ。 たとえば「吉」は最初の平面にあるが、よく似た「𠮷」は補助平面にある漢字である。

JavaScriptは、最初の平面にある文字の多くを内部で一つ分として扱う一方、補助平面にある文字を二つ分として扱う。 見た目ではどちらも一文字なので、すべての漢字を一つ分として数えると、「𠮷」そのものや後ろに続く文字を報告する位置がずれてしまう。

そこで、漢字の判定はUnicodeの文字番号単位で行い、textlintへ渡す位置はJavaScriptの数え方に合わせる処理を加えた。 その処理が必要な理由を確認したうえで、学年別漢字配当表にない漢字の検出とともに実装へ取り込んだ。

語彙やルビまで検査できれば、支援できる範囲は広がる。

しかし、一つのパッケージで扱う規則を増やしすぎると、利用場面ごとの例外も増え、設定と保守の負荷が大きくなる。そこで現在は、学年別漢字という根拠の明確な規則に絞っている。

一次資料とAIを別々の目として使う

学年ごとの漢字データは、文部科学省の小学校学習指導要領 にあるはずだと見当を付けた。仕事柄、文部科学省のサイトを調べる機会があり、一次資料へ当たりに行く道筋は分かっていた。

実際の調査では、自分で学習指導要領から学年別漢字配当表を探す一方、AIにも裏で同じ情報を調べさせた。人が見つけた情報をAIが検算するというより、別々に調べた結果を突き合わせる形である。

実装とテストコードの作成は、主にAIへ任せた。
しかし、テストが通ったという結果だけでは正しさを判断しなかった。何をテストしているのか、期待値は一次資料と一致しているかを自分で確認した。

AIには実装の速度と、見落としやすい境界条件を提案する強みがある。
その提案を採用するか、テストが仕様を確かめられているか、元データを信頼できるかは人が判断した。この分担によって、AIにすべてを任せず、かといって人力だけにも閉じない開発ができた。

textlintを知らない書き手にも届く説明

想定した利用者は、普段からプログラミングをする人だけではない。Wordやテキストエディタで文章を書いていて、ターミナルに並ぶ英単語を見ると困惑するかもしれない人も含めた。

そこでREADMEとは別に、「はじめての漢字チェック」 という導入手順を書いた。Node.jsの準備から始め、コマンドはコピーして使える形にした。

Wordのファイルを直接検査できないこと、設定ファイルが見つからない場合の確認方法、起こりやすいエラーへの対処も先回りして載せている。

説明では専門用語をできるだけ避けたが、機能の限界までは隠していない。

このルールが扱えるのはテキストファイルとMarkdownファイルであり、Word原稿は書式なしテキストへ複製してから検査する必要がある。さらに、検出できるのは対象学年では未習の漢字であって、文章全体の難しさや読みやすさではない。

ルールはあくまで検出器である。報告された漢字をひらがなへ直すか、固有名詞などの理由で残すかは書き手が決める。規則に従うこと自体を目的にせず、判断に必要な情報を返すところまでを機械の仕事とした。

npmに公開して分かったこと

完成したルールは、npmパッケージ として公開した。

npmへの公開作業そのものは、それほど大変ではなかった。久しぶりでログイン方法を忘れており、手順を調べ直したくらいだった。

公開後には、パッケージが少しダウンロードされていた。ダウンロード数を成果指標にしていたわけではない。それでも、自分の好奇心から作ったものを、知らない誰かに試された形跡は嬉しかった。

今回は同人誌の校正に関する投稿と、エンジニアリングの掛け合わせから始まった。しかし、支援できる対象を同人誌に限る必要はない。

ゲームの経験からチームマネジメントを考えることもできるし、文章を書く文化へ静的解析の考え方を持ち込むこともできる。

私が利用できる材料は、エンジニアとして身につけてきた思想、文化、技術である。
ほかの人には、その人が経験してきた別の材料がある。

自分の専門から遠く見える対象でも、持っている材料と組み合わせれば、規則化できる小さな困りごとが見つかるかもしれない。

思いついたものを小さく作り、公開してみる。

そこから技術上の発見が生まれることもあれば、これまで接点のなかった人や文化との関わりが生まれることもあるだろう。
楽しい経験だった。