Unicode テキスト境界処理覚え書き

公開:
2012-06-02

この文書は JIS X 0213 第 4 水準/Unicode 追加漢字面収録の漢字を使用しています。これらに対応していない OS/ブラウザでは正しく表示できない可能性があります。Windows では Vista 以降が標準で対応しています。

コード・ポイント

Unicode は、基本的な文字だけでも数万文字以上、規格上は百万文字近くの文字を収録する文字コード規格です。収録する「文字」にはそれぞれに独立した番号が与えられています。この値を「コード・ポイント(code point)」と呼びます。コード・ポイントは 0 ~ 10FFFF(16 進)までを取ります。

現実には、コード・ポイントという言葉は、収録されている文字に対応している整数値の意味で使われることも、ある整数値が指している文字そのものを指して使われることもあります。

コード・ポイントは U+XXXX ないし U+XXXXX という形で表記します(XXXX、XXXXX は 16 進表記)。たとえばラテン・アルファベット・大文字の ‘A’ は U+0041、ひらがなの「あ」は U+3042 といったように。

概念的には、このコード・ポイントの連続が、一般に「Unicode 文字列」と呼ばれているものになります。コード・ポイントは、Unicode 文字列を分割するときの最小単位です。

表 1. コード・ポイント
文字列 अशोक ate 𩸽![1]
コード・ポイント
U+0905

U+0936

U+094b

U+0915
 
U+0020
a
U+0061
t
U+0074
e
U+0065
 
U+0020
𩸽
U+29E3D
!
U+0021
[1]
「アショクがホッケ食べた!」の意。

ただし、このコード・ポイントの連続を実際にコンピュータ上でどのようなビットで表現するかは実装によって異なってきます。

符号化方式

最大で 10FFFF(16 進)を取るコード・ポイントを実際にコンピュータで扱うことを考えてみます。コード・ポイントの連続を実際にコンピュータ上でどのようなビットで表現するかを、「符号化方式(encoding)」と言います。

UTF-32

ひとつのコード・ポイントを 32 ビットの整数値として保持するようにした場合は話は簡単です。すべてのコード・ポイントが 32 ビットに収まるので、このような実装の場合、Unicode 文字列は 32 ビットの整数値の連続となり、このシーケンスの長さがすなわち格納しているコード・ポイントの数になります。この符号化方式を UTF-32 と呼びます。UTF は “Unicode Transformation Format” の頭字語です。

UTF-16

実際には U+FFFF までのコード・ポイントで日常使われるほとんどの文字を表現できること、ひとつのコード・ポイントに 32 ビットの空間を割り当てるのはメモリ効率が悪いことなどの理由から、コード・ポイントを 16 ビット単位で符号化することもあります。この符号化方式は UTF-16 と呼ばれます。

UTF-16 では、U+FFFF までのコード・ポイントはそのまま 16 ビットの値で格納します。U+10000 以上のコード・ポイントは次のような計算に基づいて出されたふたつの 16 ビット値を組み合わせて表現します。この組み合わせ表現をサロゲート・ペアと呼びます。

  1. 表現したいコード・ポイントの値から 0x10000 を引く。この値は 0 から 0xFFFFF の 20 ビット整数値になる。
  2. 上記で求めた値の上位 10 ビットの値に 0xD800 を足す。この値は 0xD800 から 0xDBFF になる。この値がサロゲート・ペアの先頭 16 ビット値になる。
  3. 下位 10 ビットの値に 0xDC00 を足す。この値は 0xDC00 から 0xDFFF になる。この値がサロゲート・ペアの後続 16 ビット値になる。

例として U+29E3D を考えてみます。

  1. x = 0x29e3d - 0x10000 (= 0x29e3d)
  2. hi = (x>>10) + 0xd800 (= 0xd867)
  3. lo = (x & ((1<<10)-1)) + 0xdc00 (= 0xde3d)

ということで、UTF-16 では、U+29E3D を 0xD867 と 0xDE3D の 16 ビット値の組み合わせで表すことになります。Unicode のコード・ポイントでは 0xD800 から 0xDFFF までの範囲はこの UTF-16 のサロゲート・ペアのために予約されています。

UTF-16 はひとつのコード・ポイントをひとつまたはふたつの 16 ビット値で表現するということになります。このため、UTF-16 の16 ビット値の長さは、それが表現しているコード・ポイントの長さより大きくなる可能性があります。

表 2. コード・ポイントの符号化
文字列 अशोक ate 𩸽! 長さ
コード・ポイント
U+0905

U+0936

U+094b

U+0915
 
U+0020
a
U+0061
t
U+0074
e
U+0065
 
U+0020
𩸽
U+29E3D
!
U+0021
11
UTF-32 0000
0905
0000
0936
0000
094B
0000
0915
0000
0020
0000
0061
0000
0074
0000
0065
0000
0020
0002
9E3D
0000
0021
11
UTF-16 0905 0936 094B 0915 0020 0061 0074 0065 0020 D867 DE3D 0021 12

UTF-16 で符号化している Unicode 文字列をコード・ポイント単位で処理する場合には、サロゲート・ペアの境界で文字列を分断しないように気をつけなければいけません。

グラフィム・クラスタ

すでに述べたように、コード・ポイントは Unicode に文字を収録する基本的な単位ですが、必ずしもそれがわれわれが普通に「文字」と考える単位と一致しているとは限りません。例にもあるデーヴァナーガリー文字の「शो」はヒンディー語ではこれで一文字とみなされていますが、コード・ポイントでは U+0936 U+094B ふたつの連続で表現されています。アイヌ語の表記に使う小書きの「プ」は小書きの「フ」に相当する U+31F7 (KATAKANA LETTER SMALL HU) に U+309A (COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK) を続けて表します(個人的には、「プ」を小書きにするのと、小書きの「フ」に半濁点を付けるのとは等価でないような気がしますが、とにかくそういうことになっています)。これらはいずれも、その言語の使用者からはひとつの文字であると考えられています。テキストエディタ上では、デリート・キーでの削除や、矢印キーでのキャレットの移動などで、これらをひとまとまりの文字として処理されることがユーザーに期待されます。

こうした、「利用者にとっての一文字」に相当するコード・ポイントのグループを「グラフィム・クラスタ(glapheme cluster)」といいます。なお、グラフィム・クラスタは 3 つ以上のコード・ポイントの連続になる場合もあります。

表 3. グラフィム・クラスタ
文字列 अशोक ate 𩸽! 長さ
コード・ポイント
U+0905

U+0936

U+094b

U+0915
 
U+0020
a
U+0061
t
U+0074
e
U+0065
 
U+0020
𩸽
U+29E3D
!
U+0021
11
UTF-32 0000
0905
0000
0936
0000
094B
0000
0915
0000
0020
0000
0061
0000
0074
0000
0065
0000
0020
0002
9E3D
0000
0021
11
UTF-16 0905 0936 094B 0915 0020 0061 0074 0065 0020 D867 DE3D 0021 12
グラフィム・クラスタ शो   a t e   𩸽 ! 10

グラフィム・クラスタの括りは、言語によって異なる可能性があります。たとえば、チェコ語やスロバキア語では、‘ch’ がアルファベットのひとつの文字として使われています。これらの言語では c と h の間を分断しないのが望ましいことになります。

Unicode では、こうした言語固有の事情を除いたデフォルトのグラフィム・クラスタの区切り方の仕様として、“UAX #29: Unicode Text Segmentation” が提供されています。

グラフィム・クラスタで複数のコード・ポイントがまとめて扱われるのと、UTF-16 でのサロゲート・ペアを混同しないようにしてください。サロゲート・ペアへの配慮は文字列を UTF-16 で取り扱うとき固有の事情ですが、グラフィム・クラスタによるグルーピングは文字列を UTF-32 で扱っているプログラムにも対応が求められる概念です。

ユーザーがふつう「一文字」と言うときには、このグラフィム・クラスタの単位を指していることがほとんどです。技術的な話題のときに「一文字」と言った場合、それがコード・ポイントを指しているのかグラフィム・クラスタのことを言っているのかは、しばしば曖昧なことがあります。

単語、文、行分割の境界

(執筆中)

表 4. Unicode テキスト境界(全)
文字列 अशोक ate 𩸽! 長さ
コード・ポイント
U+0905

U+0936

U+094b

U+0915
 
U+0020
a
U+0061
t
U+0074
e
U+0065
 
U+0020
𩸽
U+29E3D
!
U+0021
11
UTF-32 0000
0905
0000
0936
0000
094B
0000
0915
0000
0020
0000
0061
0000
0074
0000
0065
0000
0020
0002
9E3D
0000
0021
11
UTF-16 0905 0936 094B 0915 0020 0061 0074 0065 0020 D867 DE3D 0021 12
グラフィム・クラスタ शो   a t e   𩸽 ! 10
単語 अशोक   ate   𩸽 ! 6
行分割境界 अशोक  ate  𩸽! 3
अशोक ate 𩸽! 1

内容については正確さを心がけていますが、知識不足により間違ったことを書いてしまっているかもしれません。記事の内容によって生じた損害等について作者はその責任を負いません。ご了承ください。記事に関するご指摘やご意見ご感想はいつでも歓迎です。ゲストブックやメールなどでご連絡ください。

Copyright 2012 Masaaki Shibata <mshibata at emptypage.jp>