文字コードまとめ
幾度となく技術者たちを悩ませてきた文字コード… このあたりの知識は何度調べても毎回忘れてしまいます. というわけで調べたことをまとめて…というか並べただけです.
文字集合
US-ASCII
制御文字, 数字, アルファベット, 記号類. 7bitの範囲に収められている.
コード範囲 | 文字種 |
---|---|
00-1F | 制御文字 |
20 | 空白 |
21-7E | 図形文字 |
7F | DEL |
ISO-8859-1
Latin-1と呼ばれることもある. US-ASCIIを8bitに拡張したもの. 後半部分にはアクセントやウムラウト付きの文字や, 各国の通貨単位が収録されている.
JIS X 0201
8bit, 制御文字を除いて160文字.
前半半分の7bitはほとんどUS-ASCIIと同じ. 後半にはカタカナや句読点が収録されている.
前半7bitとUS-ASCIIの差異は以下の2つ.
コードポイント | JIS X 0201 | US-ASCII |
---|---|---|
5C | ¥(円記号) | \(バックスラッシュ) |
7E |  ̄(オーバーライン) | ~(チルダ) |
JIS X 0208
第二水準までの漢字など, 6879文字が収録されている(参考).
16bit. 正確に言うと, 基本的には7bit2バイト符号もしくは8bit2バイト符号. 図形文字のうちのSPACEと制御文字は1バイトで表現される.
8bitの数字を4桁ずつ分け, 「列/行」のように表現する方法がある. たとえば
0100 0101
は上位と下位の4bitをそれぞれ10進法に直すと4
, 5
であるため, 4/5
と表現される.
第一バイトを同じくする文字たちを「区」といい, 区の各符号を「点」という. 第一バイトと第二バイトはそれぞれ2/1
から7/14
までのbit組み合わせが許される. したがって区は94通りあり, 各区に点は94個あることになる.
この文字集合にはアルファベットやカタカナも収録されているが, JIS X 0201とは異なる符号化がなされている. 一般的には0201のものを半角, 0208のものを全角と呼び分けている.
JIS X 0213
JIS X 0208を包含する文字集合. 第三水準と第四水準の漢字が追加された. 11,233文字.
マイクロソフト標準キャラクタセット
16bit. JIS X 0201, JIS X 0208, NEC拡張文字, IBM拡張文字を統合したもの.
NEC拡張文字としては丸数字, IBM拡張文字としてははしご高などがある.
Unicode
21bit. U+XXXXという形式で表される(XXXXは4桁から6桁の16進数).
もともと16bitで世界中の文字を表現する予定だったが, のちに21bitに拡張された. 16bitまでの範囲をBMP(Basic Multilingual Plane)という.
文字エンコーディング
Shift_JIS
JIS X 0201の空き領域にJIS X 0208をマッピングする. 文字集合としてマイクロソフト標準キャラクタセットを用いる場合は, CP932と呼ばれる.
JIS X 0201に収録されている1バイト文字はそのまま1バイトに符号化される.
JIS X 0208に収録されている2バイト文字は, JIS X 0208のコードポイントとはことなる値に符号化される. 先行バイトは0201が使わない数値を割り当てることにより, 2バイト文字なのかを識別することができる.
しかし狭い領域に詰め込んだことにより, 以下の領域が重複している.
- 1バイト文字と2バイト文字の後続バイト
- 2バイト文字の先行バイトと後続バイト
したがってShift_JISの処理が不完全な場合, 意図しない符号化を生んでしまうこともある.
たとえば「ラ」の後続バイトと「リ」の先行バイトを並べると「宴」になってしまう.
文字 | 符号 |
---|---|
ラ | 83 89 |
リ | 83 8A |
宴 | 89 83 |
対処するには, マルチバイト文字に対応させること.
EUC-JP
Unix上で日本語を扱うために作られたエンコーディング.
US-ASCIIとJIS X 0208を符号化. JIS X 0201のカタカナ(いわゆる半角カタカナ)も含めることができる.
US-ASCIIはそのままコードポイントが使われ, 1バイトで表現される.
1バイトのうちUS-ASCIIが使わない後半部分を使い, 2バイト文字が表現される. しかし先行バイトと後続バイトが使う領域に重複がある. したがってShift_JISのような「ラリ宴」問題が発生しうる.
ISO-2022-JP
7bitの文字エンコーディング. エスケープシーケンスという符号により, 2つの文字集合(US-ASCIIとJIS X 0208)を切り替える方式.
JIS X 0201のカタカナには対応していない.
歴史的な理由から, 主に電子メールで使われてきた.
UTF-16
もともとUnicodeは16bitの範囲で収めようと考えていたため, それをそのまま利用する方式(UCS-2)が使われていた. その後BMP以外の文字をサポートする符号化方式として, UTF-16が考案された.
BMP以外の文字は, Unicodeの空き領域(U+D800~U+DFFF)をペアにして表現する. これをサロゲートペアという.
UTF-16には2バイトの並べ方としてビッグエンディアンとリトルエンディアンの2種類がある. たとえばコードポイントがU+3042である「あ」の場合は以下のような違いがある. ビッグエンディアンはそのままだが, リトリエンディアンは2つのバイトが逆に並んでいる.
符号 | |
---|---|
ビッグエンディアン | 3042 |
リトルエンディアン | 4230 |
リトルエンディアンはコンピュータには分かりやすいらしい. どちらの方式で符号化されているかを表すのに, BOMが利用される.
UTF-8
US-ASCIIと互換性がある. 1バイトから4バイトの可変長.
スカラ値 | 符号化パターン |
---|---|
0~7F | 0xxxxxxx |
80~7FF | 110xxxxx 10xxxxxx |
800~FFFF | 1110xxxx 10xxxxxx 10xxxxxx |
10000~10FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
例えば円記号(¥)のコードポイントはU+00A5である. これを2進数に直すと10100101
である. 上部を0で埋めて11桁にすると00010100101
となる. これを5桁と6桁に分けて上の表に当てはめると
11000010 10100101
となり, 16進数に直すと0xC2 0xA5
となる.
UTF-8には非最短形式という問題がある. 例えば上の円記号の例でいうと, 00A5
の2進数表記は
0000 0000 1010 0101
とすることもできる. すると上の表の3段目に当てはめて,
11100000 10000010 10100101
と3バイトで表すこともできてしまう.
BOM
Byte Order Markの略. テキストデータの先頭に付け加えられる数バイトのデータのこと. これにより, エンコーディングとしてUTFを使用していること, またどのUTFなのかを区別できるようにしている.
UTF-8はビッグ/リトルエンディアンの区別はないため, 単にUTF-8を使っていることを宣言しているだけ. ただしBOMをつけることを許容しているだけであって, 推奨しているわけではないらしい. むしろWebに関わるファイルにはつけないほうがいいみたい.
符号化形式 | エンディアン | BOM |
---|---|---|
UTF-8 | なし | 0xEF 0xBB 0xBF |
UTF-16 | BE | 0xFE 0xFF |
LE | 0xFF 0xFE |
Microsoft ExcelはデフォルトではShift_JISとしてファイルを読み込む. したがってUTF-8でエンコードしたCSVファイルを開くと文字化けを起こす. しかしBOMをつけていればこれは防ぐことができる.
参考
BOMなしUTF-8やShift_JIS, EUC-JPはUS-ASCIIと互換性がある(ただしShift_JISは2文字だけ異なる)ため, 英数字のみが書かれたファイルの場合, これらの文字コードに区別はない.
したがって, 英数字のみを書いたファイルにfile
コマンドを使うと, 以下のように表示されることがある.
README.md: ASCII text
改行コード
CR(Carriage Return)とLF(Line Feed)の2種類がある. システムやソフトウェアによって, 片方もしくは両方を用いる.
US-ASCIIではCRは0x0D
, LFは0x0A
である.
- LF: Unix系
- CR+LF: Windows
Rubyの正規表現では以下のようなメタ文字が用意されている.
- CR:
\r
- LF:
\n
判別方法
file
コマンドで文字コードと改行コードを教えてくれる. ただし改行コードについてはCRLF
のときだけ表示がある.
nkf
コマンドは文字コードや改行コードの変換もできる. ただしMacには標準でインストールされていない. 以下でインストール.
$ homebrew install nkf
使ってみる
$ nkf --guess foo.md
UTF-8 (LF)
文字列の置換であれば, tr
コマンドを使うこともできる.
PostgreSQLでは\l
によりデータベースの情報が取得できる. これにより文字コードも確認できる.