多言語環境とUnicode

12.4.3. 多言語環境とUnicode

はじめは言語毎に文字集合が定められましたが、 現在では世界の文字に関して共通の文字集合 Unicode (UCS) と utf-8 という符号化方法が普及しています。 全員が Unicodeとutf-8を使うように合わせれば、文字化けせずに世界の文書を扱うことができるようになりました。

文字集合 Unicode #

文字集合 Unicode は、言語言語毎に定められた文字集合を収録し、統一した番号を割り当てたものです。

Unicode の先頭の 256 文字は ISO-8859-1 ( 12.4.1. 1byteでの表現と限界 )と同じです。従って英語圏や欧州諸言語圏のユーザには、互換性のある自然な配置になっています。 Unicodeの番号で文字を指定する際は、U+ の後ろに 16 進数 4桁(以上)で表記します。つまり先頭の256文字は U+0000 から U+00FF までとなります。

65536文字 (16bit) の表を単位 (面と呼びます) に整理されていて、複数の面が定義されています。 初めの第0面 (U+0000 から U+FFFF) は 基本多言語面 (BMP, Basic Multilingual Plane) と言います。日本語もおおむねこの面に収まっています。 当初のUnicodeは1つの面 (65536文字) に全文字を収録する計画でした。

他の面 (追加多言語面や追加漢字面) に、BMP に収まらなかった漢字、 楔形文字等の古代文字、絵文字、数式用アルファベット などが収録されています。日本語のJIS 拡張漢字 (JIS X 0213) の300 字程度が、BMPではなく追加の面に収録されています。

普段どの面のどの区画の文字かを意識する必要はありませんが、 対応するフォントがあってはじめて文字を表示できることには注意が必要です。 文字によっては追加のインストールが必要かもしれません。

符号化 #

冒頭で紹介した UTF-8 は、Unicodeの文字をバイト列に符号化する方法です。 「よく使う」文字は1バイト (若い番号)、それ以外の文字は複数のバイト列 (大きな番号)を割り当てる、可変長符号になっています。

  • ASCII 文字は 1 バイト \([0,127]\)
  • 残りの文字 2バイト以上 ( \(\ge 128\) )
    • ISO-8859-1 の残り、ギリシャ文字・キリル文字などは 2 バイト。
    • 多くの和文文字(半角カナも含む)は 3バイト。
    • BMP以外 (U+10000 以上)の文字(漢字の一部を含む)は 4 バイト。
もし等長符号を使うと
これまで紹介してきた ASCII や ISO 8859-1 などでは、文字集合を定めたときの番号をそのまま文字の表現に使ってきました。 Unicodeでは、21bit (約3バイト) 必要になり、ASCII文字のコストはutf-8のときの3倍になります。

Unicodeの符号化方法は他にも沢山あります。 たとえば UTF-16 は、各文字を 2 バイトの整数倍で表します。BMP はそのまま 16 ビット (2バイト) で収められ、第1面以降はサロゲートペアと呼ばれる仕組みを用いて 4 バイトで表します。 UTF-8 と比べると、アスキー文字は1バイトから2バイトに長くなり、代わりにほとんどの日本語文字は3バイトから2バイトに短くなります。このように符号化方式にはトレードオフがあります。

注意点 #

Unicodeは、多言語を扱い、また比較的新しく導入されたことから、ユーザの立場でもいくつかの注意点があります。 日本語に関する点を紹介します。

似たような文字 #

文字の種類が増えているため、見た目が似た文字も多くなります。 たとえば次の文字列は並べると違うことは分かりますが、どれが エックスやハイフンか分かるでしょうか。
xх×⨉x×χ╳ −﹘-ー—
なれている日本語でも「ホームページ」「ホームぺージ」は、それぞれカタカナのとひらがなので表記されていますが、見た目ではほぼ区別がつきません。母国語以外の似た文字はより区別が難しくなります。

欧文では、細い文字の並びたとえば ffi のように合字 (全体で1文字) で表す習慣があります。多くは自動で適切に処理されますが、文字化けすることもあります。

文字の見分け方の一つの方法は 12.6. テキストファイルとmi で紹介します。

漢字 #

漢字は、各言語の文字集合をそのまま導入するのではなく、日本・中国・韓国で用いられている漢字が統合する作業を経て収録されました(CJK 統合漢字、CJK Unified Ideographs)。この統合には、トレードオフがあります。 メリットは、文字の表をコンパクトにできることと、言葉が違っても同じ漢字と認識できることでしょう。

デメリットは、漢字の見た目が日本語フォント・中国語フォントなどによって大きく異なるため正しいフォントを指定しないと日本語でも日本語と認識しにくいことや、各言語毎の文字の並び順との対応が複雑になることです。

濁点・半濁点の表記 #

「が」や「パ」などひらがなカタカナと濁点半濁点を持つ文字は、 複数の表現方法を持ちます。 1文字で表す方法と+と分解して表す方法です。 歴史的には前者が主流でしたが、後者にも で検索できたり え゛など独創的な表現を入力できるメリットもあります。

コンピュータにとっては異なる文字列になるため、コンピュータが「読む」文字列には注意が必要です。 たとえば、2023年時点でファイル名に濁音等を使うと、macOSは後者の表現を使い、他のメジャーなOSは前者を使うのでトラブルが生じます。

人が読むだけなら、どちらで符号化されていても同じように読めるので、問題ありません。

YEN SIGN #

本来、\(バックスラッシュ)と ¥(円記号)は別の文字です。 Unicode や、そのベースのISO-8859-1でも、 \(\texttt{5C}_{(16)}\) \ \(\texttt{A5}_{(16)}\) ¥ 半角円記号と別の番号を持ちます。

一方、歴史的に日本では \(\texttt{5C}_{(16)}\) に対応する文字を \(バックスラッシュ)から ¥(半角円記号)に置き換えて使ってきました ( 12.2. ASCII )。 過去の日本語の Microsoft Windows などでも、半角円記号になっていることが多いです。 その場合でも、どちらかしか使えないシステムの間は、人\¥ を適宜読み替えることで問題はありませんでした。 たとえば、改行をあらわす表記に \n を使いますが、過去の日本の書籍では ¥n となっているものを見ることができます。

Unicodeでは両方の文字を使えるため、 過去の日本語文書中の \(\texttt{5C}_{(16)}\) の文字がどちらかなのか、自動的に決めることは難しく、 文字コードを変換するときに問題が起こりえます。

実例

簡単に YEN SIGN 問題の実例を紹介します。ここの部分は環境によって文字が化ける可能性があります。

次のファイル test.c を用意します。これは C 言語というプログラミング言語で書かれたプログラムのソースファイルです。

#include<stdio.h>
int main(void) {
  printf("test\ntest\n");
  return 0;
}

このファイルを gcc というコマンドでコンパイルし、実行させると、test という文字列が 2 行出力されます。

gcc test.c && ./a.out
test
test

これは、ソース中の「\n」が、改行を表す特殊文字であるからです。ここの「\」は 5C(16) 番の文字であることに注意してください。

test.c は ASCII だけで書かれていますが、これをシフト JIS で書かれていると思って、Unicode の符号化の一つである UTF-8 に変換します。変換結果を、test-sjis.c とします。そして、test-sjis.c をコンパイルし、実行させてみます。

iconv -f Shift_JIS -t UTF-8 test.c  > test-sjis.c
gcc test-sjis.c && ./a.out
test¥ntest¥n

すると、出力される文字列が「test¥ntest¥n」と 1 行になり、またこの文字列の直後にシェルプロンプトが表示されました。元々のソース中の 5C(16) が、シフト JIS では半角円記号であるため、それを Unicode に変換すると ¥ (U+00A5) となってしまう(それを UTF-8 で符号化すると C2A5(16) というバイト列になる)ことによります。

しかし、Windows では、5C(16) 番の文字をディレクトリの区切りとして用いています(参考:

11.8. 階層ファイルシステム )。この関係上、CP932 と Unicode の間の変換表は、シフト JIS と Unicode の間の変換表とは違ったものとなっています。

test.c を CP932 で書かれていると思って、UTF-8 に変換してみると、5C(16) は \ (U+005C) へと変換され、バイト列としても test.c と test-cp932.c は同じものになります。よって、きちんと test の出力が 2 行になります。

iconv -f CP932 -t UTF-8 test.c > test-cp932.c
gcc test-cp932.c && ./a.out
test
test

波ダッシュ #

「にょろ」っぽい文字には複数種類があります。

チルダ~
ASCIIにある文字です。
波ダッシュ
JIS 漢字で(1 面)1 区 33 点にある文字で、Unicode では U+301C の文字です。
全角チルダ
JIS 拡張漢字でUnicodeでは U+FF5E の文字です。

過去の経緯で、波ダッシュと全角チルダは意図通りに表示できなかったり変換できないことがあります。

日本語 多言語環境とUnicode 日本語文字コードと変換