タイトル/名前 | 更新者 | 更新日 |
---|---|---|
Java/文字コードメモ2 | msakamoto-sf | 2015-02-08 00:11:31 |
Java/文字コードメモ1 | msakamoto-sf | 2015-02-08 00:11:03 |
日記/2015/02/07/Bloggerでプログラムソースコードのsyntaxハイライト(SyntaxHighlighter, Code Prettify) | msakamoto-sf | 2015-02-07 19:25:13 |
日記/2015/02/07/NetBeansでプロジェクトのバックグラウンドスキャンを止めるか無効化したい | msakamoto-sf | 2015-02-07 18:06:09 |
読書メモ/「起動プログラム ブート・ローダ入門」 | msakamoto-sf | 2015-02-07 17:55:32 |
読書メモ/"Embedded Linux Primer" | msakamoto-sf | 2015-02-07 17:48:33 |
読書メモ/「作りながら学ぶOSカーネル - 保護モードプログラミングの基本と実践」 | msakamoto-sf | 2015-02-07 17:33:28 |
技術/MacOSX/使ってるアプリメモ | msakamoto-sf | 2015-02-07 17:22:51 |
日記/2015/02/02/Galois Counter Mode (GCM)の参考メモ | msakamoto-sf | 2015-02-02 00:50:09 |
日記/2015/02/01/Web制作者向けの画面遷移図作成ツールのメモ | msakamoto-sf | 2015-02-01 16:34:39 |
Shift_JIS, MS932, Windows-31J の取り扱いについて実験する。
これらは特にサーバーサイドのJavaを扱う上で何かと文字化けの原因として取りざたされている。今回示す例では、日本語の自然文で普通に使用される '' ~ '' が簡単に文字化けしてしまっている。
特にややこしいのが"Shift_JIS"と"MS932"(CP932)系の違いである。
Windows上でのShift_JISは、正確にはShift_JISをベースとして空いている外字領域にNECやIBM由来の特殊な文字を配置したエンコーディングであり、これが "CodePage932", CP932ともMS932とも、Windows-31JともMS-Kanjiとも呼ばれているエンコーディングである。
今回の記事で例示している中で、「~」「・」は本来のShift_JISに配置されているため、これだけならコンパイル時にソースファイルのエンコーディングを「Shift_JIS」と指定してもWarningは出ない。(Warningは出ないが、実際に実行してみると文字化けする。この原因は後述。)
「㈱」が混じると、こちらはCP932で13区74点、つまり本来Shift_JISには無い外字領域に配置された文字になるため、"Shift_JIS"を指定すると文字がマップできないとWarningが出力される。
public class EncodingW31 { public static void main(String[] args) { System.out.println("Windows-31J ~・㈱"); } }
上図に示すとおり、見事に文字化けしている。下はclassファイルをUTF-8対応のエディタで文字コード自動認識で開いた図。
上図の通り、文字化けせずに表示できた。なお、エディタで開いてみると先と同じく、自動認識ではSJISと判定されてしまった。
なお、こちらの例では"MS932"としていしてコンパイルしたが、 "Windows-31J"を指定しても同じクラスファイルが生成された。 (MD5チェックサムが同一)
サーバーサイドで入力される文字コードがSJISが想定された場合は、"Shift_JIS"で受け取るのではなく"Windows-31J"あるいは"MS932"として受け取るべきである。
日本語版Windowsにより生成されたCP932の文字列を受け取ることが想定される場合は、"Shift_JIS"で受け取るのではなく"Windows-31J"あるいは"MS932"として受け取るとよいだろう。
Webアプリケーションの場合で、入力フォームがUTF-8やEUC-JPの文字コードで構成される場合は、クライアント=Webブラウザが入力フォームと同じ文字コードに変換して送信すると予想されるため、"UTF-8"や"EUC-JP"で受け取るとよいだろう。
「㈱」無しで "-encoding Shift_JIS" とした場合、コンパイルでこそWarningは出ないが、実際にうごかしてみるとやはり文字化けしてしまう。これは"~"(1区33点, 0x8160)のマッピングが原因である。
Javaは"~"について、Shift_JISとMS932で異なるUnicodeコードポイントにマッピングする。
これが、外部からの入力をJavaの内部に変換する場合のマッピングとなる。
そしてJavaの内部でのWAVE DASH, FULLWIDTH TILDEを外の世界にマッピングするときが問題となる。
Windows用のJavaVMで普通にSystem.out.println()する場合はMS932が「内→外」変換として使われる(PrintStreamの文字列出力は、プラットフォームのデフォルトの文字エンコーディングを使ってバイトに変換される)。
従って、"-encodign Shift_JIS"でコンパイルしたclassファイル中の「~」(U+301C WAVE DASH)はMS932ではマップされないため、"?"として文字化けすることになる。
Javaソースコード中に埋め込まれた文字列が、実際にコンパイルされると内部で本当にUTF-8になるのか確認してみる。
プラットフォームはWindowsXP + JDK 1.5
重要:Javaクラスファイル中のUTF-8についての追加情報を本文末に追記したので、そちらも必ず参照のこと。
EncodingSJIS.java: public class EncodingSJIS { public static void main(String[] args) { System.out.println("ShiftJISの日本語表示文字列です。"); } }
DOS> javac -encoding Shift_JIS EncodingSJIS.java DOS> java -cp . EncodingSJIS ShiftJISの日本語表示文字列です。
public class EncodingEUC { public static void main(String[] args) { System.out.println("EUC-JPの日本語表示文字列です。"); } }
DOS> javac -encoding EUC-JP EncodingEUC.java DOS> java -cp . EncodingEUC EUC-JPの日本語表示文字列です。
拡張子を.txtにして(しなくとも良いが)、UTF-8に対応したエディタで文字コードをUTF-8で指定して開いてみる。
いずれも、文字コードがUTF-8としてエディタに認識され(*1)、実際に日本語文字列が読み込めている。
以上より、 -encoding オプションをコンパイル時に指定することによりプラットフォームのデフォルトでない文字コードでも、クラスファイルコンパイル時にUTF-8に変換されて内部表現されることが分かった。
では、あえて-encodingで間違ったエンコーディングを指示するとどうなるか?
上図のように、コンパイル時に文字コードの検出で警告が表示されるが、クラスファイルは生成される。また、実行すると文字化けしていることが分かる。
実際にクラスファイルをエディタで開いてみると、下図のようになり、エディタの文字コードの自動認識も失敗していることが分かる。
どうでもいいですが、文字コードとエンコーディングをもうちょっと意識して使い分けたいです。勉強しなくちゃ・・・。
元々Javaクラスファイル中の文字列がUTF-8である、というのは、たまたまクラスファイルをsakuraエディタで開いてみた時、日本語部分がきちんと表示されたのがUTF-8で開いたときだったからと言う経験に基づいた推測にすぎなかった。
実際にJavaVM仕様書を見てみると、classファイル中での文字列はUTF-8で表現するよう記述されている。
この記事では最初からUTF-8であることが分かっていたような順番で書いてしまっているが、実際は先に経験上UTF-8で文字化けしないことが分かっており、その後仕様書で確認したところUTF-8で合っていた、という順序だった。
ただしUTF-8と表記されていても、classファイル中でのUTF-8は標準とは若干異なるエンコーディングになっている。
There are two differences between this format and the "standard" UTF-8 format. First, the null byte (byte)0 is encoded using the 2-byte format rather than the 1-byte format, so that Java virtual machine UTF-8 strings never have embedded nulls. Second, only the 1-byte, 2-byte, and 3-byte formats are used. The Java virtual machine does not recognize the longer UTF-8 formats.
The Unicode strings, despite the moniker "UTF-8 string", are not actually encoded according to the Unicode standard, although it is similar. There are two differences (see UTF-8 for a complete discussion). The first is that the codepoint U+0000 is encoded as the two-byte sequence C0 80 (in hex) instead of the standard single-byte encoding 00. The second difference is that supplementary characters (those outside the BMP at U+10000 and above) are encoded using a surrogate-pair construction similar to UTF-16 rather than being directly encoded using UTF-8. In this case each of the two surrogates is encoded separately in UTF-8. For example U+1D11E is encoded as the 6-byte sequence ED A0 B4 ED B4 9E, rather than the correct 4-byte UTF-8 encoding of f0 9d 84 9e.
ポイントとしては 標準のUTF-8ではなくUTF-8によく似ているが若干異なるエンコーディングを行っている点。U+0000のNULL文字など、VMSpecの方に詳細なコードポイントの範囲と変換方式が載っている。
BMP(=UCS-2)の外のコードポイントについての記述がVMSpecとWikipediaとで異なる点が気になる。
VMSpecの方では
Second, only the 1-byte, 2-byte, and 3-byte formats are used.
The Java virtual machine does not recognize the longer UTF-8 formats.
として、単に「認識せず」としか書かれていない。
UTF-8で3バイトまでの範囲となると U+0000 から U+FFFF までになるので、UCS-4でのBMP(=UCS-2)の範囲になり、JavaVM内部ではUnicode(UCS-2)の文字集合が使われている、という話と一応矛盾はしないが、Wikipediaの記述とずれがある。
Wikipedia側の記述:
The second difference is that supplementary characters (those outside the BMP at U+10000 and
above) are encoded using a surrogate-pair construction similar to UTF-16 rather than
being directly encoded using UTF-8.
これについては、WebのVMSpecの方が記述が古くなっているのが原因らしい。WikipediaのReferenceにはJSR202へのリンクがあるが、これが Java Class File Formatの最新版となっている。
こちらを確認したところ、
Characters with code points above U+FFFF (so-called supplementary characters)
are represented by separately encoding the two surrogate code units of their
UTF-16 representation.
としてU+10000以降のコードポイントの変換方法がきちんと掲載されている。Wikipediaの説明はこちらを参考にしていると思われる。
今回は「たまたま」通常のUTF-8と同じエンコードになる範囲の文字列だったため、sakuraエディタで開いて文字化けせずに済んだだけだったことが分かる。
http://java.sun.com/docs/books/jvms/second_edition/html/VMSpecTOC.doc.html
上記VMSpecのドキュメントは、Web上でJavaVMの仕様を確認できる便利なページではあるが、今回のようにJSRの方で更新されている部分もあるため注意が必要かもしれない。
SyntaxHighlighter:
Code Prettify:
SyntaxHighlighterでのトラブル:
SyntaxHighlighterの現在の開発はこちら:
結構なんとかしてほしい、と思ってる人が多いようだ。
が、どうもNetBeansの必須機能として、プロジェクトのバックグラウンドスキャンが必要らしく、無効化したり止めるような簡単なというか、NetBeans公式の方法は無いらしい。(唯一、プロジェクトをcloseしておけばOK、程度)
一応プラグインで自動的なバックグラウンドスキャンを無効化し、必要になった時だけ実行できるようにするプラグインもあるにはあるが、開発用ビルドでないと動かないとかなんとかで、普段使いには出来そうにない。(ので、試してもない)
2015年2月時点、NetBeans 8.0.2 まででの結論→諦める。
2009年頃までにだらだらと読んだ一冊。
複数のCPUアーキテクチャでのブートシーケンスについて説明し、ブートローダの開発で必要な知識をまとめてくれてる。
複数種類のアーキテクチャを扱っている分、それぞれのアーキテクチャについての解説は薄い。あくまでもブートローダをどうするか?という点に絞ったノウハウ書なので、必要に応じて読むタイプの本。
またその内容から、初心者や入門者を対象とはしておらず、組み込みシステムの開発経験を前提としている。
正直、この本が「勉強になった」というよりは、この本に関連した周辺知識を深めてくと、OSやカーネルレイヤーにも親しみやすくなるという一冊。
併せて読みたい:
あとブートローダで忘れちゃいけない一冊:
※これ、FreeBSDのブートプロセス解説したバージョンもあったんだけど、そちらはさすがに新装版は無いか・・・。
組み込み以外の分野の人が、組み込みLinuxの世界に入る時に、予め全体像を把握しておくのに最適な一冊と思われます。もちろんこれ一冊だけでOKというわけではなく、詳細は各章末尾の参考資料に目を通すことになるでしょう。
"Primer"な本ですので、「すでにカーネルのcompileやmakeの構造は知り尽くしてるし、gdbつかったりkgdb使ったりも日常的にしてて、アセンブラとC言語の境界も問題ない」という方には物足りないと思います。
組み込みに本気で取り組みたいとか、Linuxカーネルのソースの詳細を今すぐ調べなければならない、というわけではないのだけれど、「そもそもLinuxカーネルのコンパイルってどうなってるの?」とか、「vmlinuxとかvmlinuzってなによ?」など、Linuxカーネルの詳細な解説よりは概要を知りたい、という自分にはぴったりでした。
2009年~2010年頃に読んでて、読書メモシリーズにまとめる前だったので、後から探すのにいつも苦労してたので、こちらにメモ。
x86アセンブラでOSやカーネル系を触るときに避けて通れない「保護モード」について、ブートストラップから組み立てていくことで勉強できる流れになっている。
Amazonのレビューに「内容は良いのだが、誤植が多い」という主旨がいくつか投稿されてるが、個人的にも同感。
2009年当時から環境や開発ツールなど変化し、そのままでは動かないケースもありそうだが、自分としては当時、これが大変良い教材で、「はじめて読む486」の技術知識をこちらの書籍で手を動かして学べたので、思い出深い一冊。
併せて読みたい:
使ってるアプリのメモ。2012~2013頃に揃えたので、もしかしたら最近だとインストールできなかったり公開やめたのもあるかも。
ブラウザ
エディタ
日本語入力
ネットワーク系
ファイルの圧縮と解凍
AVプレイヤー
その他
Cacoo, FreeMind, iEditあたりが有名か?
次点で、テキストからノード構造をパースして、画面遷移図っぽい画像に変換するBlockdiagというツールがあるらしい。
また、ユーザの行動を遷移図に組み込んだ「UI Flow」という書き方もあるようです。
以上、メモ書きでした。