まず前提知識として、次のことを知っておいてください。
- Atom(というよりJavaScript)は文字列を全てUnicode(正確にはUTF-16)で扱っており、文字コードの選択に関わらず、エディタ上では全てUnicodeで処理している。指定の文字コードへのデコード/エンコードはファイルの読み書き時に発生する。
- Unicodeには全角幅のチルダがU+301C
〜
とU+FF5E~
の二つ存在する。(Unicode 8.0からはこの二つの文字は同じグリフになったため、同じ文字のように表示されますが、実際のコードポイントは異なります。)
Atomで書き込み時のエンコードをどこで行っているかは下記のようになっています。
- エディタで表示編集するファイルに対する操作はAtomのコアから切り離されて、text-bufferパッケージで行っている。
- text-bufferではpathwatcherのFileを使用している。
- pathwatechrのFileではUTF-8__以外__でエンコードする場合はiconv-liteを使ってエンコードしてからファイルを書き込んでいる。(UnicodeからUTF-8への変換はNode.jsに組み込まれているため、Node.jsをそのまま使用)
ファイルの読み込みも同様にiconv-liteでデコードしています。
iconv-liteが変換に使っているのがマップ表であるeucjp.jsonです。この中ではU+FF5E~
は"a1c1"
と"8fa2b7"
の二つに割り当てられていますが、U+301C〜
は割り当てられていません。このため、読み込みでは
- A1 C1 => U+FF5E
- 8F A2 B7 => U+FF5E
となりますが、書き込みでは
- U+301C => 3F ※ 割り当て無しのため
?
に変換
- U+FF5E => 8F A2 B7 ※ A1 C1 より後のためか、エンコードはこちらが優先される。
となります。
その他、Shfit_JISおよびその亜種のCP932についてまとめると下記のようになっています。
|Unicode|名称|文字|UTF-8|JIS X 0213|EUC-JP|Shfit_JIS|CP932|
|---|---|---|---|---|---|---|
|U+301C|WAVE DASH|〜
|E3 80 9C|1-1-33|3F(?
)|3F(?
)|3F(?
)|
|U+FF5E|FULLWIDTH TILDA|~
|EF BD 9E|1-2-18|8F A2 B7|81 60|81 60|
※ JIS X 0213の1-2-18には通常のチルダU+007E~
も割り当てられています。
※ EUC-JPは A1 C1 も読み込め、同じ 8F A2 B7 と同じU+FF5Eに変換されます。
※ 3F はASCIIの?
であり、割り当て無しのための代替文字として使われています。
8F A2 B7 は何かというとJIS X 0213(JIS補助漢字)での2-23です。EUC-JPとしてはある意味正しいですが、ある意味正しくありません。なぜなら、他の実装は次のようになっているからです。
- U+301Cを A1 C1 に割り当て、U+FF5Eは何も割り当てていない。(変換もできない)
- EUC-JPの3バイト表記(8Fや8Eから始まる)に対応していない、または、8E(半角カタカナ)のみ対応している。そのため、8F A2 B7 は変換不可で文字化け等が起きる。
そのため、相互にEUC-JPとなった文字をやり取りするときに、おかしな動作を行います。
結論としては、iconv-liteの不具合と考えられます。しかし、チルダ問題は現状実装依存であり、これが正解という変換が存在しません。よって、現代的なプログラミングにおいては、全てをUTF-8で統一することが現実解と思われます。
それでもEUC-JPを使い続けたい場合はiconv-liteをforkして、マッピングのJSONを編集し、それを読み込むようにAtomをハックするしかないでしょう。
(iconv-liteにissue#145として投げました。修正されれば、そのうち直るかと思います。)
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/01/29 01:42
2017/01/29 02:28
2017/01/29 04:49
2017/01/29 06:12
2017/01/29 07:21
2017/01/29 07:40