AutoHotkey:文字エンコーディングに対応する
Image by Stable Diffusion
ブログはObsidianを扱い出すようになってから再開したが、Obsidianを単体で利用するよりは、外部アプリの利便性も活かしたい。
そういう意味ではAutoHotkeyは、応用力の高い面白い言語だと思う。
日本語は2バイト文字だ。
文字コードは今やUTF-8(可変長マルチバイト文字)全盛で、言語圏に関わらず扱える点では日本人でもありがたい話だが、一昔前のWebでは日本語を表示するのに、Shift-JISやEUC-JPといった日本語専用2バイト文字コードを使っていた。
ObsidianにURLからWebブログカードを貼るのに、Auto Card Linkプラグインという便利なものがあるが、残念ながら一昔前のWebサイトが想定されておらず、Shift-JISやEUC-JPのWebサイトURLを貼ると文字化けしてしまう。
前置きが長くなったが、Auto Card Linkプラグインを使わずにAutoHotkeyから文字エンコーディング判別するスクリプトをChatGPT君とやりとりして提案してもらった。
WinHttpよりダウンロード
AutoHotkeyからWebにアクセスする手段はとりあえず二択。
ComObjCreateでWinHttpやXmlHttpでオブジェクトに取得
UrlDownloadToFileでローカルにダウンロードする
アクセスしたとしても一時ファイル的なものなので、WinHttpで何とかしようとしていたが、AutoHotkeyは取り込んだ時点でUTF-8として読み取ってしまうらしく、Shift-JISやEUC-JPのWebサイトは文字化けしてしまう。
ChatGPT君と30分くらいあーだこーだした末に提案されたのが、UrlDownloadToFileで一度ローカル保存してしまう方法。
渋々試すと、文字エンコーディングが保たれた状態のファイルだった。
一度ローカル保存してから、そのファイルを読み込んでUTF-8にエンコーディングすることで目的に達することができた。
ただし文字エンコーディングを判別する手段は「とりあえず何かの文字コードにエンコードして、特徴ある文字化けが含まれていたら次を試す」という力業だった。
他の言語やAPI使わずだとAutoHotkeyではこの辺りが限界の模様。
スクリプト例
以下はUTF-8、Shift-JIS、EUC-JPのWebサイトを文字化けすることなくエンコーディングするAutoHotkeyスクリプトのサンプルです。
文字コード判別に使う文字はサンプルのものでダメな場合もあるので、お手元でいろいろ試してみてください。
なお、ISO-2022-JPは特殊すぎるのと、それで書かれたWebはさすがにレアすぎるためスルーしました。
Shift-JISのWeサイト例
KENT-WEB
https://www.kent-web.com/pubc/garble.htmlEUC-JPのWebサイト例
一般財団法人 日本防火・防災協会
https://www.n-bouka.or.jp/sitepolicy/
vURL := "https://~~"
vTmp := "<Your Local Folder>\tmp.html"
FileDelete, % vTmp
UrlDownloadToFile, % vURL, % vTmp
; ファイルのエンコーディングを判定し、UTF-8に変換する
vHTML := ""
if FileExist(vTmp) {
; UTF-8での変換に失敗した場合
if InStr(vHTML := ConvertFileTo(vTmp, "UTF-8"), "�") {
; Shift-JISでの変換に失敗した場合
if InStr(vHTML := ConvertFileTo(vTmp, "Shift-JIS"), "") {
; EUC-JPに変換
vHTML := ConvertFileTo(vTmp, "EUC-JP")
}
}
}
FileDelete, % vTmp
ConvertFileTo(vFilePath, vEncoding) {
oStream := ComObjCreate("ADODB.Stream")
oStream.Open()
oStream.Type := 1 ; バイナリーモード
oStream.LoadFromFile(vFilePath)
oStream.Position := 0
oStream.Type := 2 ; テキストをバイト列に変換
oStream.Charset := vEncoding
sText := oStream.ReadText()
oStream.Close()
Return sText
}