文字コード再入門 ─ Unicodeでのサロゲートペア、結合文字、正規化、書記素クラスタを理解しよう!

文字コードには、どのような種類があり、それぞれどのような意味を持つのか、といった、文字コードの基本的な概念、従来の文字コードを紹介し、現在のUnicodeの構成を概説し、プログラミングにおいて注意すべき箇所をいくつか取り上げます。

文字コード再入門 ─ Unicodeでのサロゲートペア、結合文字、正規化、書記素クラスタを理解しよう!

ソフトウェア開発に携わる方の多くは、何らかの形で文字コードに触れることがあるでしょう。文字や記号をコンピュータ上でデータとして扱うには、文字コードの知識が必要不可欠です。

本稿では、書籍『プログラマのための文字コード技術入門』の著者である矢野啓介さんが、知っておきたい基礎知識を分かりやすく解説します。

文字コードとは?

コンピュータで文字を扱うには、平仮名の「あ」やアルファベットの「A」といった文字ごとに一意な符号化表現(バイト列)を割り当てます。この割り当ての規則を文字コードと呼びます。ISOやJIS等の規格では、符号化文字集合(CCS、Coded Character Set)という用語が使われます。

歴史的な経緯から、英数字100文字程度の小さくシンプルなものから、世界中の文字を収めた大規模かつ複雑なものまで、さまざまな文字コードが世界各地で作られてきました。

Unicode以前の文字コード

ここでは、現在主流になっているUnicodeが普及する以前の主要な文字コードを、ごく簡単に紹介します。

最もシンプルな文字コードは、1文字を1バイトで表す1バイトコードです。国や地域ごとにバリエーションがあります。

ASCII
米国のANSI規格。0x21~0x7Eの範囲に英数字を収録する7ビットの1バイトコード
JIS X 0201
日本規格。ASCII類似の7ビットの1バイトコードであり、それに加えて8ビット(0xA1~0xFE)の範囲に片仮名のコードを用いることができる
ISO/IEC 8859-1
ASCIIに加えて、アクセント記号付きアルファベット等を収録した西欧諸言語向けの8ビットの1バイトコード。通称、Latin-1

また、東アジアでは、1文字を2バイトで表す2バイトコードも実用化されてきました。

JIS X 0208
日本の漢字、平仮名、片仮名等を収録。1978年初版。第1・第2水準漢字を含む6,879文字。コンピュータの日本語処理の実現に貢献
JIS X 0213
JIS X 0208に足りない文字を追加した拡張版。2000年初版。第3・第4水準漢字を含む、現代日本で使用実態の認められた11,233文字
GB 2312
中国規格。JIS X 0208と類似の構造で、簡体字の漢字を収録
KS X 1001
韓国規格。JIS X 0208と類似の構造で、ハングルと漢字を収録

上記の符号化文字集合を組み合わせて使う運用方式として以下があります。これらを文字符号化方式(CES、Character Encoding Scheme)と呼ぶことがあります。

EUC-JP
ASCIIとJIS X 0208を組み合わせたコード。7ビット部分(0x7F以下)はASCIIそのもので、8ビット部分(0xA1~0xFE)に2バイトコードを配置。Unixの日本語化で採用。中国や韓国でも、同様の構成でGB規格やKS規格を用いるEUC-CNやEUC-KRが採用された
ISO-2022-JP
ASCIIとJIS X 0208をエスケープシーケンスで切り替える7ビットのコード。インターネットメールで長年使用された
Shift_JIS
JIS X 0208を計算式によって変形した上で、JIS X 0201の隙間に詰め込んだコード。PCや携帯電話等で広く利用された

これら3つに対する拡張版が、JIS X 0213でそれぞれEUC-JIS-2004、ISO-2022-JP-2004、Shift_JIS-2004として用意されています。

このように多数の文字コードが世界各地で策定され使用されてきましたが、これでは国や地域ごとに文字コードを使い分ける必要があります。そこで、ひとつの統一的なコードで世界中の文字を扱えるように、Unicodeが開発されました。

Unicodeとその主な符号化形式

Unicodeは、ユニコードコンソーシアム(Unicode Consortium)という非営利法人によって公開されています。初版は1991年リリース。最新は13版(2020年3月10日)で、絵文字や記号も含む世界各言語の計143,859文字が収録されています。

1 The Unicode Standard

当初のUnicodeは、16ビット固定長のコードとして開発されました。現在では、整数値で表現される符号位置を、UTF-8・UTF-16・UTF-32といった符号化方式によってバイト列へと符号化する形態を取っています。符号位置とは、文字コード表のマス目の位置と思えばよいでしょう。

Unicodeには、16ビットすなわち65,536の符号位置を持つ面(plane)が17面あり、合計100万あまりの符号位置を持ちます。符号位置は「U+4E00」のように接頭辞「U+」を付けた4~6桁の16進数で表記します。

17面あるうち、最初の面00が基本多言語面(BMP、Basic Multilingual Plane)であり、日常的に用いる文字の大半がここに収められています。

Unicodeの主な符号化方式の概略を以下に記します。

UTF-16

UTF-16は、16ビットを1単位として用いる符号化方式です。BMPの文字については、符号位置の整数を16ビットで表したビット組合せがそのままUTF-16の値になります。

ただし、16ビットに収まらないBMP以外の面の文字は、サロゲートペアという仕組みを用いて表現する必要があります。BMPの中のD800からDBFFまでが上位サロゲート、DC00からDFFFまでが下位サロゲートとして用意されており、上位サロゲートと下位サロゲートの2つの16ビットの組み合わせによって、BMP外の1つの符号位置を表します。

また、16ビットの単位を8ビットのバイト列に直列化する際に、上位・下位どちらの8ビットを先にするかというバイト順の問題が生じます。上位を先にするビッグエンディアンはUTF-16BE、下位を先にするリトルエンディアンはUTF-16LEと呼ばれます。

バイト順を見分けるため、データの先頭にBOM(Byte Order Mark)という特殊な符号位置(U+FEFF)を置く方式が採られることがあります。バイトを逆順にしたU+FFFEには文字を割り当てないことが保証されているため、どちらのバイト順か見分けられます。

UTF-32

UTF-32は、32ビットを1単位として用いる符号化方式です。符号位置の整数を32ビットで表したビット組合せがそのままUTF-32の値になります。

全ての符号位置は32ビット以内で表せるので、UTF-16と異なり、サロゲートは必要ありません。ただし、UTF-16と同様にバイト順の問題はあるため、やはりBOMが用いられることがあります。

UTF-8

上記のUTF-16・32はバイト単位でASCIIと互換ではありませんが、UTF-8はASCII互換の符号化方式です。Unicode符号位置の範囲に応じて、1~4バイトの長さを取る可変長のコードです。

ASCIIと同等の範囲は、1バイトで表されます。アクセント付きアルファベット等は2バイト、漢字や平仮名等は3バイトになります。BMP外の符号位置は4バイトを要します。

UTF-16・32と異なり、バイト順の問題は存在しませんが、UTF-8の印としてファイル先頭にBOM(U+FEFF)が付けられることがあります。EF BB BFという3バイトです。

Webで文字コードを指定する仕組み

Webでは、主にUTF-8が用いられています。HTMLやCSS等の仕組みは特定のコード系に依存するものではありませんが、コード変換のトラブルを避けるため、新規に開発するものはファイルや入出力のコードをUTF-8にそろえておくと何かと便利であり、現在の慣例となっています。

HTML文書で文字コードを指定する

HTMLでは、meta要素によってそのHTML文書の文字コードを指定できます。UTF-8で符号化されたHTML文書では、head要素内に下記のように記します。

<meta charset=”UTF-8”>

なお、これはHTML5で導入された記述方法です。それまでのバージョンでは下記のように記していました。

<meta http-equiv=”Content-Type” content=”text/html;charset=UTF-8”>

HTTPのプロトコルで文字コードを指定する

HTTPのレスポンスヘッダで、サーバから送信されるHTML等のコンテンツの文字コードを指定できます。コンテンツの種類をContent-Typeフィールドで示しますが、これがテキストの場合は、オプションとしてcharsetパラメータを指定し、文字コードを示すことができます。

下記の例では、サーバから送信されるHTML文書(text/html)の文字コードがUTF-8であることを表しています。

Content-Type: text/html; charset=utf-8

パラメータcharsetに与える文字列は、IANA charset registryにて定義されています。シフトJISなら「Shift_JIS」、日本語EUCなら「EUC-JP」などとなります。大文字小文字は問いません。

このパラメータはHTMLコンテンツに限らず、プレーンテキスト(text/plain)等にも適用可能です。

Unicodeによるプログラミング上の注意点

エンジニアHubに会員登録すると
続きをお読みいただけます(無料)。
登録のメリット
  • すべての過去記事を読める
  • 過去のウェビナー動画を
    視聴できる
  • 企業やエージェントから
    スカウトが届く