【解決】自作DenoモジュールでMS-IMEのユーザー辞書ファイルを生成したいので試行錯誤する
今回、ユーザー辞書ファイル生成モジュール『bId』でMS-IME対応を行ないたいので、その試行錯誤を記録する(だいたいは先人のマネになると思う)
今のところGoogle日本語入力は確実に動作する(ことえりはCSVを吐き出す処理を書いたけど動作確認してない)
出力ファイルを見る限り、エンコードはUTF-16LEらしい
このときのMS-IME対応の機能要件
- TSVで出力
- エンコードをUTF-16LEに変更
ファイル作成には自作ユーティリティモジュールを使っていたが、そのときはエンコードについては考慮されていなかった。
内部的に利用していたDeno.writeFile
のオプションを眺める限り、エンコードの指定はない。
利用しているnew TextEncoder()
にエンコードが指定できるのかと思ったけど、UTF-8以外は指定できない模様。
じゃあどうするんじゃいとなって調べたところ、以下記事にやりたいことが書いてありそうだった
この記事に書かれていたnpmパッケージが便利そう、記事作成者と同じようにskypackで導入したらすんなり入った
encoding.jsを利用して各種エンコーディングに対応
外部から入ってくるUTF-8を、任意のエンコードに変更することができるようになる。
これで解決と思ってUTF-16LEを指定してファイル出力をしたところ、VS Codeでは『バイナリか対応していないエンコードです』なる警告が表示された。IME自体の出力ファイルは問題なく読めたので不穏な気配を察知、MS-IMEで読み込むもファイル形式の違いで全件弾かれる。
その後、改めてMS-IMEの出力ファイルについて調べたところ、BOMが必要ということに気づく。
BOMとはそもそもなんぞや、ということでWikipediaを見る。
バイナリの接頭辞として追加されるものだという雑な理解をする。当初は手動でBOMを追加しようとしていたが上手く行かず、encoding.jsのドキュメントを読み返したところ、encoding.js自体にBOMの追加機能があることを知る
encoding.jsのBOM追加機能を使えるようにユーティリティライブラリを書き直す。
モジュール側もエンコーディングとBOM追加ができるように変更済み。
UTF-16LEがエンコードだとわかっていたので、エンコードはUTF-16、BOMはLEに指定する。が、エンコーディング対応のときと同じようにVS Codeで表示されず、全件が弾かれるという結果になる。
おそらくエンコーディングをUTF-16LEにせずにUTF-16にしたからではないかと予測、次の試行錯誤に持ち越し。
ホントにエンコードが想定しているものになっているのか怪しくなってきたので、検出ツールがないか調べる。以下記事がヒット。
記事中にnkfというオープンソースツールの紹介があり、これで確認ができるらしいことがわかる。
OSDNからインストールすると手動で構築する必要があるが、Makefileの知識がなかったため上手くいかなかった。
調べたところ、macOSではHomebrewが、WindowsではScoopの非公式Bucketでインストールできることがわかった
Homebrew(macOS BigSur)
brew install nkf
を実行すればインストールできる。
nkf -V
で動作確認可能。
Scoop(Windows 10 Home)
非公式BucketのURLは以下。
scoop bucket add jp https://github.com/dooteeen/scoop-for-jp
で非公式Bucketと紐づけ、
scoop install nkf
を実行すればインストールされる。
動作確認はHomebrewと同一。
nkfで調べた結果、そもそもバイナリとして出力されていることがわかった。
PS D:\_system\User\Documents\web\dictionary> nkf -g .\dist\msime_development.txt
BINARY
windchime-yk@WhyK dictionary % nkf -g dist/msime_development.txt
BINARY
指定しなければ変換処理が走らないので、MS-IME対応のところのみ問題が発生しているのは正しい。
PS D:\_system\User\Documents\web\dictionary> nkf -g .\dist\google_development.txt
UTF-8
windchime-yk@WhyK dictionary % nkf -g dist/google_development.txt
UTF-8
ファイル作成処理がおかしいのかもしれない。
ファイル作成処理の単体試験を確認したが、作成されるファイルはUTF-16LEだった。
その後の処理に問題がある?
単体試験を更新したが、バイナリファイルとして表示される
windchime-yk@WhyK deno-util % nkf -g test/folders/file4.txt
UTF-16
ただし、nkfでの判定はUTF-16。
ファイルにUTF-16文字列を入れたためだと思われるので、合わせてreadFileも修正したほうがいいかもしれない。
CI環境としてはUbuntu:latestなので、Ubuntuで出力した際にバイナリに変換された?
DockerでUbuntu仮想環境を構築して確認する。
よく考えたら前段確認作業でWindowsローカル実機での出力結果がバイナリなので、CI環境は無関係だった。
GitHub Actionsのubuntu-latestは現状だとUbuntu 20.04
試しにWindowsでもバイナリになるか試したが、こちらもUTF-16として出力された。
PS D:\_system\User\Documents\web\deno-util> nkf -g .\test\folders\file4.txt
UTF-16
この時点でファイル作成処理側の問題ではなく、利用側つまりbIdの問題であるとわかった。
現状のまとめ
- deno-utilのファイル作成処理はWindowsやmacOSでも正常に動作している
- bIdを利用して出力すると、MS-IME用のファイルがバイナリとして出力される
- ローカル環境でバイナリとして出力が確認されている以上、CIは関係ない
現状の結論
bIdの実装側に問題がある。
確認方法素案
deno.test()
内部でnkfを動かして文字コードを判別するものを書く。
nkfをDeno.spawn()
で実行して結果を受け取るイメージ。
MS-IME対応は据え置きになったので一旦クローズするが、時間を置いて調査を再開する。
Node互換性でBufferがあり、これで実装可能ということをゴリラさんに教えていただいた。
import { Buffer } from "node:buffer";
const utf8string = "->😃🧒🏼üčē<-";
const buf = Buffer.from(`\ufeff${utf8string}`, "utf16le");
await Deno.writeFile("utf16le.txt", buf);
手元で試したところ、問題なく動作したので、これで上手いこといかないか試してみる
\ufeff
がわからなかったので調べたところ、これがUTF-8におけるBOMらしい。
試しにこれを外してみたところ、以前見たエラーとなったため、以前のものはBOMがないからエラーになった可能性がある。
対応完了。
ゴリラさんに感謝……。