About

*

文字コードの考え方から理解するUnicodeとUTF-8の違い

公開日: : 最終更新日:2015/02/13 技術, 文字コード

UnicodeとUTF-8の違いを理解していない方が結構居るようなので、文字コードの考え方を元に解説してみようと思う。

文字コードとは何か?

文字コードとは、コンピュータ上で文字を扱うために、文字に対して割り当てられた数値のことであり、文字と数値の対応付けと呼べる。

この対応付けの種類は沢山あって、Shift-JISであったり、UTF-8であったりする。
以上!と言いたいけど、文字コードはこんなに単純ではない。文字コードを複雑にする要素は沢山あるが、今回の記事ではUnicodeとUTF-8の違いに焦点を絞って解説してみたいと思う。

文字コードの構成要素

文字コードの世界は以下の2つの要素で構成されている。 この違いを意識しておかないと混乱を招くだろう。

(1).文字集合 – 表現したい文字の範囲(”あ”、”い”・・・といった文字の集合体)
(2).符号化方式 – 文字集合を構成する個々の文字の表現方法(数値の振り方)

世界中には日本語や英語、ドイツ語、中国語・・・など、大量の文字が存在する。これらの文字から表現したい文字の範囲(集合体)を定義する。これが(1)の文字集合だ。

次に(1)の個々の文字をコンピュータ上でどういった数値で表現するかを定義する。この数値の振り方が符号化方式(2)である。コンピュータはこの(2)で割り当てられた数値を用いて文字を表現する。

この文字集合と符号化方式を混合している方がよく居るが、この2つの考え方を理解すればUnicodeとUTF-8の違いも分かるだろう。
つまり

Unicodeは文字集合(1)であり、UTF-8は符号化方式(2)なのだ。

同じようにUnicode用の符号化方式としてUTF-16やUTF-32が存在する。
これらはUnicode文字集合に対する数値の振り方こそ違うものの、同じ文字集合から作られているから、表現できる文字の種類は同じなのだ。

unicodeimage-1

なぜUnicodeとUTF-8を混合してしまうのか?

そもそも文字コードに興味の無い人が多くて、UTF-8はUnicodeの一部ような、ぼんやりしたイメージしか持っていない人が多い。強いて言うなら以下の2つだと思う。

Unicodeを符号化方式として扱っているソフトウェアの存在

よくネタとして挙がるのがWindowsのメモ帳。ファイルを保存する場合、以下の文字コードを選択できる。UTF-8の他に「Unicode」と「Unicode big endian」なるコードも選べてしまう。

windows7notepad

この表示、文字集合と符号化方式について理解していても混乱してしまう。
Unicodeって文字集合だよね??
符号化方式ではないのにファイル保存の形式に選べるってどういうこと??

実はWindowsのメモ帳でUnicodeを選択した場合の符号化方式は「UTF-16」と決められている。
「Unicode」と「Unicode big endian」は同じUTF-16だがエンディアンが異なる。

参考 – エンディアンとは
エンディアンとは複数バイトで構成されるデータの並べ方の事で、ビッグエンディアンとリトルエンディアンがある。例えば「0xABCD」という、2バイトのデータがあったとき、これを「ABCD」と並べるか「CDAB」と並べるかが異なる。前者がビッグエンディアン、後者がリトルエンディアンである。人の目から見ると「ABCD」の方が分かりやすいけど、コンピュータ視点で見ると「CDAB」の方が操作しやすい。
(計算は下の桁から始めるから、下位バイトが先に読み込めた方がコンピュータ的には都合が良い。人には見にくいけど)

試してみた。
Windowsのメモ帳でUnicode、Unicode big endian、UTF-8で保存したファイルをそれぞれ用意。
ファイル内の文字はすべて同じ。

$ ls
Unicode.txt		UnicodeBigEndian.txt	utf-8.txt

$ cat utf-8.txt
あいうえお
一二三四五

まず、文字コードの確認

$ nkf --guess utf-8.txt
UTF-8 (CRLF)

$ nkf --guess Unicode.txt
UTF-16 (CRLF)

$ nkf --guess UnicodeBigEndian.txt
UTF-16 (CRLF)

やはり「Unicode.txt」、「UnicodeBigEndian.txt」は両方ともUTF-16みたいだ。

ついでにエンディアンも確認

<2015/2/13 – 下記、エンディアンの判別方法を修正しました。リトルエンディアン・ビッグエンディアンの記載が逆となっておりました。>

今回はodコマンドを利用してファイルのバイナリ表現を出力する。odコマンドはエンディアンに依存した出力を行うため、1バイト単位で区切って出力するために-t x1オプションを付与して実行する。
(今回の環境はリトルエンディアン環境のため、-t x1を付与しないとリトルエンディアンを意識した出力(前後逆にする)となってしまう。)

$ od -t x1 Unicode.txt
0000000 ff fe 42 30 44 30 46 30 48 30 4a 30 0d 00 0a 00
0000020 00 4e 8c 4e 09 4e db 56 94 4e

$ od -t x1 UnicodeBigEndian.txt
0000000 fe ff 30 42 30 44 30 46 30 48 30 4a 00 0d 00 0a
0000020 4e 00 4e 8c 4e 09 56 db 4e 94

やはり「Unicode.txt」はリトルエンディアンで、「UnicodeBigEndian」はビッグエンディアンだ。
ちなみに、エンディアンはファイルの先頭2バイトで確認できる。
この2バイトの事をBOM(ByteOrderMark)といい、エンディアンの判別に利用される。
(BOMが付与されていない場合はビッグエンディアンとして扱われる)

BOMが
「fffe」の場合:リトルエンディアン
「feff」の場合:ビッグエンディアン
と判別できる。

コードポイントが紛らわしい

文字集合にはコードポイントという符号化方式とは異なる数値の振り方がある。

コードポイントとは?

文字集合では、個々の文字に対して、文字集合内での符号位置が決められている。これをコードポイントという。
言い方を変えると、「文字集合を構成する文字を並べて、頭から順番に振った数値」のことだ。
このコードポイントはあくまで”その文字の文字集合内での位置”であり、符号化方式ではない。

例えば「ほげふが」のUnicodeのコードポイントは以下の通りである。

文字コードポイント
U+307B
U+3052
U+3075
U+304C

このU+XXXXはただの符号位置を表す数値なので、この値でデータを保存しても意味が無い。
文字を表現したい場合はコードポイントではなく、符号化されたByte列を用いる必要があるのだ。
このコードポイント、ぱっと見で符号化方式に見えてしまう。この点を理解していない方は混乱すると思う。

コードポイントの利用場面

コードポイントは様々な場面で利用されている。例えばJavaのプロパティファイル(.propertiesファイル)に日本語を記述する場合などだ。

Javaのプロパティファイルは文字コード「ISO-8859-1」で記述するというルールがある。
「ISO-8859-1」はほとんどASCII文字しか扱えなから、表現したい文字のUnicodeコードポイントをプロパティファイルに記述する。
例えば、「message=こんにちは」といったプロパティを定義する場合、

message=\u3053\u3093\u306B\u3061\u306F

と定義する必要がある。
\uは後続の文字がコードポイントを表していることを指し、その後ろにコードポイントを記載する。コードポイントの指す文字は「こんにちは」であるが、コードポイント自体は数値とアルファベットでのみ構成されるため、「ISO-8859-1」でも問題無く保存できるという訳だ。
この文字からコードポイントへの変換は通常IDEが自動的に実施するが、ファイルの実体はUnicodeコードポイントで表現されている。
また、「native2ascii」を使えばファイル内の「ISO-8859-1」が表現できない文字を手動でUnicodeコードポイントに変換できる。
※ ちなみに、J2SE 5.0からはxml形式のプロパティファイルを扱えるようになり、これをを利用すれば自由に文字コード指定できるようになった。

これ以外にもUnicodeコードポイントを利用する例は多々あるが、コードポイントは符号位置(文字集合内の文字の位置)であって、符号化方式ではない。そのためコードポイントはUnicodeの符号化方式であるUTF-8やUTF-16とは直接は関係しない。

簡単だけど、文字集合と符号化文字をまとめてみた。
文字コード関連では他にも色々とおもしろいネタがあるので、今後も時間を見て書いていくことにする。

関連記事

「Systemd」を理解する ーシステム起動編ー

2014年6月10日、とうとうRHEL7が正式リリースを迎えた。RHEL7での変更点については、この

記事を読む

「Systemd」を理解する ーシステム管理編ー

前回の記事「Systemd」を理解するーシステム起動編ーでは、Systemdの概念とSystemdに

記事を読む

Java8のインタフェース実装から多重継承とMixinを考える

2014年3月18日、ついにJava8が正式にリリースを迎えた。 折角なので、今後、Java8の新

記事を読む

例示専用のIPアドレスとドメインを使いこなす

前回の記事ではネットワークに関する記事を投稿させていただいたが、今回も引き続きネットワーク関連のネタ

記事を読む

Ctrl+Cとkill -SIGINTの違いからLinuxプロセスグループを理解する

しばらくLinuxネタが続く・・。 近いうちに最近出たJava8ネタを書いてみようと思います。が、

記事を読む

Linuxプロセス起動時の環境変数ダンプの取得

UnixやLinux上で不具合の調査等々を行う際、特定のプロセス起動時の環境変数を知りたい場合がある

記事を読む

ipsetを使ってスマートにiptablesを設定する

ギークな知人から「vpsでiptables設定していたらルール設定数の上限に引っかかって思い通りの設

記事を読む

Java8のHotSpotVMからPermanent領域が消えた理由とその影響

今回も前回の記事につづき、Java8による変更点で未だあまり紹介されていないポイントを記事にしようと

記事を読む

sshd再起動時にssh接続が継続する動作について

Linux/Unixサーバにsshしている際、sshdを再起動したとする。 sshdは一度終了する

記事を読む

Comment

  1. TrevorMon より:

    Enjoyed the images, i truly like the one of %image_title%, perfect.

    my website – http://journal-cinema.org/

  2. ip より:

    はじめまして、文字化け問題を検索していてたどり着きました。

    WordPressを使用しており、テーブル作成が簡単に行えるTablePressというプラグインを導入しました。
    csvファイルを読み込んでテーブルを作ることもできるそうなので、試してみたところ文字化けが起こって困っていました。

    多くの人はUTF-8(BOM)なしで解決できているそうなのですが、私の場合解決に至らず困っていました。

    文字化けの仕方がこの記事に書かれている「u」から始まる英数字でした。

    “テスト”と入力すると”u30c6u30b9u30c8″となってしまいます。

    こういった場合はまずどこを疑えば良いべきなのでしょうか・・・。教えていただけませんでしょうか。

  3. しのぶ より:

    「Unicode.txt」と「UnicodeBigEndian.txt」の結果が逆になってませんか?

    > feff 3042 3044 3046 3048 304a
    はUTF-16 Big Endianで
    > fffe 4230 4430 4630 4830 4a30
    はUTF-16 Little Endianだと思うのですが。

    > BOMが
    > 「feff」の場合:リトルエンディアン
    > 「fffe」の場合:ビッグエンディアン
    > と判別できる。

    これも逆だと思います。

    バイトオーダーマーク – Wikipedia
    http://ja.wikipedia.org/wiki/%E3%83%90%E3%82%A4%E3%83%88%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%E3%83%9E%E3%83%BC%E3%82%AF

    • ブログ主 より:

      >しのぶ様
      コメントありがとうございます。内容確認しました。
      ご指摘の通りリトルエンディアンとビッグエンディアンの記載が逆となっておりました。
      失礼しました。記事の内容は修正しております。

      なお、記事中でファイルのバイナリ表現の取得にodコマンドを利用しておりましたが、odコマンドはエンディアン依存の出力を行うため、筆者のリトルエンディアン環境では、前後逆表記となったバイナリ表現が出力された状態(実際のファイル内容とは異なるバイナリ表現)となっておりました。
      odコマンドに-t x1オプションを指定し、1バイト単位でのバイナリ表現を取得することでエンディアンの置き換えが行われないよう記事は修正しております。(併せてエンディアンの判別部分も記載を修正しております)

      今回はご指摘いただきありがとうございました。

  4. 榎本俊二 より:

    文章がわかりやすく大変参考になりました

  5. 通りすがり より:

    >符号化方式(文字集合を構成する文字の表現方法)
    の画像の中の「UTF-8」の「あ」の文字コードは
    「e38182」ではないでしょうか

  6. 匿名 より:

    大変参考になりました

  7. […] >>Unicodeは文字集合(1)であり、UTF-8は符号化方式(2)なのだ。 http://equj65.net/tech/charcode/ […]

  8. 匿名 より:

    参考になりました

  9. 萩原 より:

    とても参考になりました!
    IT業界で働いて5年目にして初めてしりました(笑)
    ありがとうございます!!

  10. 匿名 より:

    やっとユニコードが何なのかわかりました
    ありがとうございます

  11. dindi より:

    UnicodeはUnicode consortiumが定義した符号化文字集合及び文字符号化スキームを含む規格の総称であり、符号化文字集合(ご記事にある「Unicode」)はUCS(Universal Character Set)で、UTF-8は“Unicode Transformation Format-8”の略で文字符号化スキームのうちの1つであると理解していました。よってUnicodeはUCSとUTF-8を両方を含むと…。

Message

メールアドレスが公開されることはありません。

「Systemd」を理解する ーシステム管理編ー

前回の記事「Systemd」を理解するーシステム起動編ーでは、Syst

「Systemd」を理解する ーシステム起動編ー

2014年6月10日、とうとうRHEL7が正式リリースを迎えた。RHE

例示専用のIPアドレスとドメインを使いこなす

前回の記事ではネットワークに関する記事を投稿させていただいたが、今回も

ipsetを使ってスマートにiptablesを設定する

ギークな知人から「vpsでiptables設定していたらルール設定数の

Java8のHotSpotVMからPermanent領域が消えた理由とその影響

今回も前回の記事につづき、Java8による変更点で未だあまり紹介されて

→もっと見る

PAGE TOP ↑