- 2013/4/9 10:30-12:30(くらい)
- 文字コードの話
- オレは文字コードが嫌いだ
- BOMって知ってる?
- JIS系コード
- CP932とは…
- 改行コードの話
- 実習
- スピードとレイテンシの話
- スピードのオーダー
- 西濃運輸は神
- 計算量の話
- 計算量のオーダー
- O(1)
- O(logN)
- O(N)
- O(NlogN)
- O(N)
- 文字コードとは?
- UTF-8
- Shift_JIS
- JIS X 0208
- JISコード
- Unicode
- UTF-16
- EUC-JP
- JIS X 0202
- ISO-2022-JP
- JIS X 0213
文字コードと聞いて思い浮かべるキーワードはたくさんあるんだけど、これが体系的に整理できている人はそんなに多くない。
- 文字コードっていうのは非常に曖昧な言葉
- 整理できていない人が文字コードの話をすると以下の2つが混ざっている
- 文字の集合(coded character set)
- 文字の符号化方式(character encoding schema)
整理するとこんなかんじ
文字集合(文字コードセット) | 符号化方法(文字エンコーディング) |
---|---|
Unicode | UTF-8 |
| UTF-16 (BE/LE)
| UTF-7
JIS X 0208 | Shift_JIS / CP932 | EUC-JP | ISO-2022-JP
- 16bit/32bitのデータの格納方法はどうする?
- たとえば 0xABCD をファイルに保存したらどうなるか?
- 0xAB 0xCDと保存するか、0xCD 0xABと保存するかはCPU次第
- これをエンディアンという
- 0xAB 0xCD と保存する → ビッグエンディアン
- 0xCD 0xAB と保存する → リトルエンディアン
- Intel x86 CPUはリトルエンディアン
- ARM CPUはビッグエンディアン
- バイエンディアンだがネイティブはビッグエンディアン(だったはず)
- Javaはビッグエンディアン(ネットワークバイトオーダーに一致させている)
-
エンディアン問題が出やすい場所
- 他のマシンにファイルを持っていったとき
- ネットワークでバイナリを送信したとき
-
OSIはビッグエンディアンでネットワークにバイナリを流そうと言っている
- 「ネットワークバイトオーダー」というのはビッグエンディアンのこと
- C APIに htons, htonl というのがありよしなにビッグエンディアンにする
-
odコマンドで確認できるよ!
-
od -t x (xIで4バイト、xSで2バイト、xCで1バイト)
- 一般的にはJIS X 0208のこと
- ちょいちょい拡張されてJIS X 0212とかJIS X 0213がでてる
- 日本のJIS規格で決まってる
- 符号化方式は附属書に載ってるけど実用化されてるのはShift_JISくらい
ノリとしては0208 + 0212 = 0213的にとらえれば大体OK(0212に入ってるけど0213に入ってない文字はある)。0213で増えた文字はマニアック(?)なやつばっかりなので、実用上は0208だと思っておけばよい。ただし、0208から0213で同じコードポイントで字形が変わったものがあり、フォントによっては0213の字形で出てくるものもある。具体的には葛飾区の「葛」とか。
- あ : 2422
- じゃあバイナリエディタで0x24 0x22と書き込んだファイルを作ろう!
- ポチっとな…
- あれぇ…
はい、できないですね。なんでかというと0x24はASCIIコードで$、0x22はASCIIコードで " だからです。単にJISのコードポイントをバイナリに落としてもASCIIコードと一緒にまぜて運用できないため、特定のルールに従って符号化する必要があります。
- Shift_JIS
- ASCIIで使ってる領域を1バイト目に出さないようにする方式
- EUC-JP
- JIS X 0208のコードに0x8080加算した値を保存する方式
- 半角カナとかは3バイト使ってマッピングする
- ISO-2022-JP
- 制御文字を使ってASCIIとJISの切れ目を明示する
- 7bitで転送できる(ので、メールなどで使われた)
実用上はこの3つを覚えておけばよい。むしろこの3つ以外に思いつかなかった。
- いまバージョン6.0 か 6.1くらいだったはず
- 201x年代のWebはJIS X 02xx系使っていいのは小学生までだよねーみたいな雰囲気あります(本当か?!)
- U+XXXXXX という書き方でUnicode文字集合の1つの文字を特定する(XXXは16進数)
- あ: は U+3042
-
簡単に言うと
- Unicodeの最初のほうは1バイト
- わりと前のほうは2バイト
- 真ん中らへんは3バイト
- 結構うしろのほうは4バイト
- いま割りあたってないところは5バイトとか6バイト使う
-
身近なところでいうと?
- ASCIIコードは1バイト
- 日本語は3バイト
- 基本的にはUTF-8のほうがサイズがでかくなるね
ほぼASCIIコードしか埋め込まれていないようなソースコードだとサイズに差がでませんが、逆に日本語しか入ってないドキュメントはJIS系にくらべて1.5倍くらいになります。
が、このご時世にあんまりShift_JISで書くことにこだわる意味が無いので普通にUTF-8でファイルを作っておけばよいかと思います。ただし、昔のUTF-8に対応してないコンパイルでソースコードを書く、などの場合は除きます(いまどき新卒がそういう環境に放りこまれることはまれです)。
- 作った当時は16bitで収まりそうだったから16bit固定で保存するようにした。
- しかし中国4000年の歴史で大量の漢字が存在するため16bit(約65000文字)では足りないことが判明
- 実際、TRON系の超漢字では18万文字の文字をサポートしている
- そこでサロゲートペアを導入
- 上位サロゲート1024文字x下位1024文字の組み合わせを使い、4バイトで100万文字を表現できる使用を追加した
UTF-32? とりあえず使う人そんなにいなさそうなので省略である。ちなみにC++11ではchar16_tやchar32_tっていうUTF-16やUTF-32を格納できる方が追加されてた(これ最近知った)。
- U+FEFF というコードのことをByte Order Markとよぶ
- ただし、これは俗名である
- U+FEFFの正式な名前は ZERO WIDTH NO-BREAK SPACE
- 幅ゼロで改行禁止のスペース
- なんじゃそれ
- 表示に1ピクセルも影響を与えないスペースという定義の文字
- これを埋めておいても表示上の影響はない
- これを読み込んでエンディアン判別に使おう!
- 間違ったエンディアンで読み込むと 0xFFFEになる
- じゃあU+FFFEは予約文字ということにして使用しないようにしよう
- ファイルの最初にU+FEFFを埋め込んでUTF-16 BE/LEの判別に使おう!
- Byte Order Markと呼ばれるようになった
UTF-16はかならず2バイトずつのセットで文字を保存するが、1バイトずつ読み込んだときにどちらがHIBYTEでどっちがLOBYTEなのかがわからない。それを解決するために、BOMを埋め込んでどちらがHIBYTEなのかがわかるようにしている。もし2バイト読み込んでシーケンスが[0xFE, 0xFF]でも[0xFF, 0xFE]でもないときはUTF-16のビッグエンディアンとして取り扱うことになっている。
- 西濃運輸は神 のコピペで考えるとわかりやすい
プルル…プルルル
俺「はい、もしもし」
西濃「おるかーー?」 (SYN)
俺「え…?ど、どちらさまでしょうか…?」 (ACKSYN)
西濃「よーし、おるな!いくわ!」 (ACK)
俺「え、え!?」
ピンポーン、ガチャ
西濃「ここやで、トントン(はんこ押すとこを指で叩きながら)」 (データ送信開始)
西 濃 は 神
UDPは電話確認せずに来るイメージ(つまり佐川急便である)。