昨日の続き。

<Kindle版>


<楽天Kobo版>


<ラトルズネット版>(販売予定)
https://www.rutles.net/

昨日は大体こんなことを書いた。
 ・テキストファイルをダンプ(16進)表示すると文字コードが分かる
 ・「改行」もテキストファイルの中で文字コードになっている
 ・改行コードはUNIXでは0x0A、Windowsでは0x0D0Aと非互換がある
 ・FTPのテキストモードで送信すると改行コードは変換される
 ・FTPのバイナリーモードで送信すると改行コードは変換されない
 ・Windows改行のPerlスクリプトをUNIXで実行すると、シュバング行にゴミが入るのでうまく実行できない

なお、ブログは行数が限られているので、以下のことは省略した。
 ・テキストファイルとバイナリーファイルの違い
 ・0x0D、0x0Aというコードのそもそもの意味
 ・16進数の数え方

これらについて知りたい方は拙著「文字コード【超】研究」を読まれたい。

16進数の数え方とか、普通に中学で習うと思っていたのだが、会社に入ってみると大のオトナで数えられない人がボロボロいるのである。
まあ中学で習ったことを社会人になって忘れることぐらいあるだろう。
ぼくもテニスコートの誓いのいきさつとか保元・平治の乱のいきさつとか忘れてしまった。

昔はパソコン(マイコン)の本と言うと16進数の数え方で始まっていたのだが、最近はマルチメディアとかデザインパターンとかアジャイルがどうしたとかいう超難しい話は出てくるが16進数の数え方は出てこない。
では16進数の数え方なんか覚えなくてもパソコンなんか使えるようになったかというと、そうはなっていなくて、バリバリ使うのである。
このへんが一昨日も少し書いた情報処理界の「必要とされる知識と当然知っている知識」のマッチングの欠如という「世の中のバグ」の一つの表出である。
ということで、世の中のデバッグの一助として、ぼくは自分の本に大きくバランスを崩して16進数の数え方を書いた。
このへんがおぼつかない人はこの機会に読むといいのではないだろうか。

さて、昨日は、WindowsのテキストファイルをUNIXにバイナリーモードで送った場合、改行コードの非互換によって変なことになる例とその解決法を紹介した。
これは本当に昔じぶんで遭遇して、相当困った問題である。

基本文字コードの問題は、こういう目に見えない文字、あるいは見た目に分かりにくい字が犯人のものが多い。
全角のスペース とか、半角カナの句点。とかである。
こういうのは16進数ダンプすると大体分かる。

今日はもうひとつ自分で遭遇した問題を紹介しよう。
ある日、UNIXサーバーから持ってきたファイルを開くとこんな風に文字化けしていた。
(著作権に関係ないところで夏目漱石の草枕(青空文庫版)を使う)

mojiA


文字化けしている。
しかし、面白い文字化けである。
最初しばらく読めているが、途中から化けている。
しばらく化けているかと思うと、また途中から持ち直す。
化け文字と読める文字が交互に出てくる。
これをシマ状文字化けと呼ぶ。
(いや、そういう学術用語があるわけではなく、いま勝手にぼくが作った用語である。)

さてなぜ起こるのだろうか。
とりあえずダンプしてみるとしよう。

mojiB


ああ、なるほどそういうことかー。
ぼくぐらいの玄人になるとそう思うが、まあ説明しよう。

最初が0xFEFFで始まっている。
これはBOMと言って、UTF-16BEのファイルであることを示している。
UTF-16BEはUnicodeの一種で、基本的に1文字16ビット(まれに32ビット)の文字コードである。

続く0x3000は全角スペース、次の0x5C71は山、次の0x8EDFは路であろうかと思われる。
漢字に関してはUnihan Database(http://www.unicode.org/charts/unihan.html)というUnicode Consortiumが用意しているオンラインデータベースで検索することが出来る。
「山」だとこのように検索されて「UTF-16」では「5C71」だと分かる。

さて、UTF-16BEではいわゆる「半角ローマ字」、つまりABCなどの字も16ビットになっている。
先日メモ帳で作った

ABC(改行)DEF

というファイルはASCIIという文字コード系で作られていたが、中身は16進数で

41 42 43 0D 0A 44 45 46

だった。

これらの文字が、UTF-16BEでは

0041 0042 0043 000D 000A 0044 0045 0046

のようになっている。

と、言うことを知って、知りつつ上のダンプを見ていると、途中に

000D 000D 0A30 0066

という変な字の並びがある。

(これが変だ、と気が付くのには半年ほど修業が必要である。)

これは本来

000D 000A 3000 66..

と言う風になるはずだった。つまり、Windows改行(0x000D 000A)の後ろに全角空白(0x3000)が来た状態である。

しかし、UNIXサーバーからWindowsにFTPのテキストモードで持ってきたので、000Aが000D0Aに変更されてしまったのだ。

つまり、UTF-16BE(あるいはUTF-16LE)であればテキストであってもバイナリーモードでダウンロードする必要がある。FTPのテキストモード(正確にはアスキーモードと言う)が適切に機能するのは、ASCII、Shift_JIS、EUC-JP、または同じUnicodeでもUTF-8など、「改行がASCIIの範囲内」のものだけだ。

UTF-16は16ビットまたは32ビット、つまり16ビットの整数倍である。
つまり16ビットごとに字の切れ目が大体来る。
しかし、000A(16ビット)が000D0A(24ビット)に変更されてしまったところで、余計な8ビットが挿入されてしまった。

だから、改行以降はすべて、半文字ずつズレて解釈されてしまったのだ。

ところが、文字化けしているのはしばらくの間で、このファイルは途中から持ち直す。
(シマ状に化けている。)
これはどういうことかというと、また改行がくるからである。

さきほどの8ビット(UTF-16半文字)分のズレに対して、改行がもう1回文字化けする(余計な8ビットがもう1回挿入される)ことによって、ちょうど1文字分(16ビット)のズレになる。
よって次の字から化けなくなる。

よって、このタイプの文字化けは、改行が1回挿入されるごとに(夏目漱石が行を変えるたびに)

 正しく読める=>改行=>化ける=>改行=>正しく読める=>改行

のパターンを繰り返す。

これがシマ状文字化けのカラクリであった。

ではどうやって直せばいいのだろうか。
ぼくはこういうとき考えるのがめんどくさいのですぐPerlを使うが、「バイナリーエディター」が手元にあればそれを使えばいいような気がする。
要は「000D0A」を「000A」に一括置換すればいいのである。
あるいは、FTPをバイナリーモードにしてもう一度同じファイルをダウンロードすればいい。

こういうことが660ページに渡ってびっしり書いてある本である。
電子書籍なら2500円で買えるので、興味があれば是非お買い求めくだされば幸いである。

このエントリーをはてなブックマークに追加