文字コード覚書

文字コードの話は正確にやろうとすると大変なので適当に書いてみる。

文字集合:文字を集めたもの

JIS X 0208
Unicode

符号化方式:文字集合に番号をつけたもの

ISO-2022-JP
EUC-JP
Shift_JIS

コードセット

文字集合の集合、EUC-JPではASCII+JIS X 0208+その他

実際の文字コード:1バイト

US-ASCII:0から127まで使う標準的な半角英数文字と制御コード

128から255までをどう使うかでいくつかの文字コードがある

ISO-8859-1はドイツ語のウムラウトとかアルファベットの上に何らかのマークがつく文字を収録していてヨーロッパでは基本の文字コード、WindowsではWindows-1252ともいわれる。

ISO-8859-5はキリル語(ロシア語)の文字だがあんまり使われずKOI8-Rが使われるらしい。

実際の文字コード:2バイト以上

欧米件は文字数が少ないので1バイトでよかったが、漢字圏では足りないので2バイト以上になる。

Shitf-JIS:最大2バイト

もともと日本語はJIS X 0201でASCIIでつかってなかった領域にカタカナを収めて1バイトで使っていた。

漢字が表示できるようになってからは、この1バイトの使ってない領域を2バイト文字へ移行する制御コードとして使い、2バイトを利用して漢字を表現していた。

Cプログラムなどで問題になるのは2バイト文字の2バイト目が\などになった場合である。例えばパスを¥で区切るプログラムを単純に作っているとこの2バイト目の¥に引っかかっておかしくなってしまう。

EUC-JPやUTF8では2バイト目以降のバイトにこれらのASCIIは入らないのでこのような問題は起こらない。

ソフト業界が国際化してからはWindowsではUTF16を使いLinuxではUTF8を使うことが多い。UTF16は基本的に2バイト固定なので文字操作はしやすいが欧州圏からみるとメモリがもったいない。

Unicodeでは¥とバックスラッシュは区別されているが、JIS X 0201のASCII部分も実は若干変わっていてバックスラッシュのところに¥を割り当てている。文字コード変換などでShift-JISからUnicodeに変換したときもし¥がそのままUnicodeの¥になってしまうと困るので運用上はASCII部分は変換しない慣習になっている。逆にUNICODEの\(U+00A5)からShift-JISに変換した場合はバックスラッシュに変換してしまう。よってさらにこれをUNICODEに変換したら元の文字列と同じにならないことになる。日本語環境では今後もバックスラッシュにお目にかかることはないのだろう。

UTF8で書いていて本当にバックスラッシュを表示したい場合はHTMLなら

と書けばいいようだ。実際書いてみる→\

Windowsでのプログラム

Windowsでは文字コードをコードページという言い方をしているようだ。

MultiByteというのは日本語環境ならShift-JISというように、Unicode以前の2バイト以上文字列のことでWindows98とかのころのOSのデフォルトの文字コードのことだろう。

WideChar、ワイド文字とはUTF16をさす。

第一引数のCodePageは入力文字列のコードページだがCP_ACPを指定すればOSのデフォルト設定が使われ日本語WindowsならShift-JIS(codepage932)になると思われる。もっとも昨今のWindowsはこのデフォルトのコードページを変えられると思われそれは、言語設定の非UNICODEアプリの設定になると思われる。

ロケールとの関係

Cライブラリにはmbstowcsがあり、これで変換できる、LC_CTYPEがマルチバイト文字列をあらわしている。

コンパイラ

最近のコンパイラはUNICODEで保存されていてもOKなのでリテラル文字列を国際化できる。一般にはコードはASCIIのみがよいとされているものと思われるが。

VC2008ではファイルの保存で文字コードを選択できるので以下のようなコードが書ける。

XPでの実行結果

xpi18nmessage

Windows8での実行結果

8int18

コンソールで表示

wprintf()などで上のプログラムの文字列を表示しようとしてもほとんど表示できない。CRTは内部でマルチバイトにしてしまうためだとおもわれる。

以下のように強引に書いてもマルチバイトとして表示してしまう。

もともとコンソールはワイド文字仕様になっていないものと思われる。

Ubuntuのコンソールで実験

gccで上のプログラムを普通にコンパイルしても–input-charset=utf8 –exec-charset=utf8などのオプションをつけても以下のようにちゃんと表示されなかった。catなどではちゃんとutf8ファイルを表示出きるのでできると思うがいまはスルー。

PHPとMySQLの文字コード

formからPOSTのシナリオ

1、formからポスト

ブラウザはページのキャラセットでサーバにデータを送る。<form>タグでキャラセットを指定してある場合もある。携帯の場合は常にshift-jisで送ってくる場合もある。

2、PHPが受取る

PHPが受取る際には、ディレクティブmbstring.encoding_translationが有効であれば、入力エンコードをmbstring.http_inputに設定されているエンコーディングとして扱い内部エンコーディングmbstring.internal_encodingに変換する。mbstring.http_inputが”pass”であれば何もしない。これらのディレクティブはphp.iniなどで設定するかApacheのコンフィグで設定する。.htaccessが利用できればここでも設定できる。以下は.htaccessで設定した例。

<IfModule mod_php5.c>
php_flag  output_buffering              Off
php_value output_handler                none
php_value default_charset               euc-jp
php_value mbstring.language             japanese
php_flag  mbstring.encoding_translation On
php_value mbstring.http_input           pass
php_value mbstring.http_output          pass
php_value mbstring.internal_encoding    euc-jp
php_value mbstring.substitute_character none
</IfModule>

3、PHPがMySQLサーバに送る。

PHPはサーバに接続後、”SET NAMES xxx”を使ってエンコーディングを設定できる。デフォルト値はMySQLのサーバ変数character_set_connectionで指定される。MySQLは受取ったデータをこの値でエンコーディングされているものとして扱う。をMySQL ver4以上は内部的にはUTF8でデータを持っている(character_set_system)ので、このデータをUTF8に変換して保存する。データベースやテーブルにはcollationという属性があるが、これはテーブルデータを”ORDER BY”で並び替えるときに使われる。

character_set_connectionの実行時の値を確認するには、MySQLコマンドラインから、”SHOW VARIABLES;”を発行する。

とここまで調べたが実際にはcharacter_set_clientとかもあって非常にわかりずらいのでスルー。