サロゲートペアってなんでコワイの


Puppeteer1でE2Eテスト用スクリプトを書いていたら、type2でサロゲートペア打ち込むと化けるというバグに遭遇したので。

「サロゲートペアに注意しろって言われても、サロゲートペアって何なんだ……?」という人向け。
(いろいろ細かいところはすっ飛ばしています)

コンピュータと文字

まず当然の話ですが、コンピュータ、というよりもコンピュータを構成する計算機は文字を認識できません。まあ計算機ですし。
しかし、人間様としてはまさかコンピュータの発する電気信号を直接読み取るわけにも行かないので、なんとか文字を扱えるようになって貰う必要がありました。

そこで頭のいい人が考えたのがいわゆる文字コードです。

グリフと符号と集合と

さて、コンピュータに文字を"覚えさせる"にあたり、文字というものは2つの概念に分離されました。

第一の概念はグリフ (glyph, 字形/字体) です。
ちょっと意識しづらいかもしれませんが、これは文字通り字そのもの、字の形、キーを叩いたら出てくる文字の形をした画像のことを意味している、と思ってもらえばOKです。

第二の概念は文字に対応するものです。コンピュータにとっては文字符号3 (文字コード) です。
人間は、文字を見ると対応する意味や音を想起することができます。AにはAの音があり、「字」という字には「字」という意味があります。
コンピュータは数値なら扱えます。ということで、文字を扱う時は、文字それぞれに予め数値を割り当てておいて、その数値を取り扱うことでなんとかすることになっています。これが文字符号です。

これら「グリフと文字符号の対応付け」を集めたもののことを、符号化文字集合と呼びます。
そして、この対応付けを実際にコンピュータ上で取り扱う時どのようにするかという決まりごとのことを文字符号化方式と呼びます。
通常、このあたりのことを意識せずに「文字コード」という場合、大抵はこの文字符号化方式のことを指しています。ややこしいですね。

Unicodeの登場

さて、そんなこんなで世界中が頑張った結果、様々な符号化文字集合と文字符号化方式が乱立します。当然ですね、文字はいっぱいありますから。ヨーロッパでもアルファベットの変種が山ほどあるのに、アジア方面なんかどうすりゃいいのかと。

そんな中、Unicodeという構想が持ち上がりました。
字面とこの流れでだいたい想像はつくかもしれませんが、このUnicodeは「全世界のあらゆる文字を1つの符号化文字集合の下統一しよう」という凄まじいスケールの構想でした。
パワープレイもいいところですが、コンピュータとその関連機器の性能向上によってこれはあながち夢物語でもなくなってきたのです。

そして、Unicodeは実際に動き出し、様々な国、地域から文字の登録を受け付けていきます。
……

Unicodeの敗北

Q. 何があったの?
A. 表現できる文字の量が足らない

「16bit、65536種分の領域があれば、あらゆる文字を格納できる!」
これが、Unicodeの初期の構想でした。しかし、足りなかったのです
Unicodeの理想、これは伊達ではありません。なにしろ、Unicodeには普通のアルファベットからルーン文字や錬金術文字まで、文字通りにあらゆる文字が登録されようとしていますといっても残念ながらアーヴやヒュムノスはないんですが

Unicodeの人たちは考えました。困ったことに「こりゃどうやら足らんぞ」とわかったのはUnicodeがとっくに走り出した後。既に各所で実装されており、今から「やっぱなしな!」とか言い出したら確実に計画崩壊、どころか世界中大混乱です。
しかし、UnicodeがUnicodeたらんとするのであれば、文字容量は増やさねばなりません。

というわけで、おまたせしました。サロゲートペアの登場です。

サロゲートペアの登場

サロゲートペアは、未使用の領域2つの組み合わせで1文字を表現することにすることで、擬似的に表現できる文字量を増やすというものすごい苦肉の策だったのです!

……ええと、要するに「ここからここまでの数値が来たら、もう1文字分読み込め。んで、2つ合わせて1文字扱いしろ」ということです。

ここまでくればピンと来たかもしれません。
そう、サロゲートペアが何故ここまでめんどくさがられ恐れられているのか。
1文字だと思ったら0.5文字だった
こういう事態を引き起こすから、サロゲートペアは恐れられるのです。

ところで実際

では実際どうすればよいのでしょう?

実は、意外にも難しいことはあまりありません。というのも、サロゲートペアの存在を意識して、サロゲートペアに対応したライブラリやAPIを使えば、そこまで問題は起こらないからです。だってみんな面倒は嫌ですから、誰かが対策打ちますよそりゃ。
もしもあなたがサロゲートペアで痛い目を見るとしたら、それはバグか、古いアプリケーションによるもののことがほとんどでしょう。私はそれで「うがー!」となっています。

なお、実際に取り扱うデータにおいてサロゲートペア云々の問題が発生するのは、実は文字符号化方式にUTF-16を採用している場合のみです。
……のみなのですが、あいにくとUTF-16を文字列の内部表現として使っている言語は少なくありません。結局は、割とどこでも起こりうるめんどくさい問題、と思っておいたほうがよいかもしれません。


  1. GoogleのE2Eテストその他向けライブラリ。ChromeをNode.jsから触れる。 

  2. 特定のコントロールに文字列を(字面通り)タイプする。例えば page.type("#hoge", "ほげ") とやるとpageのid=hogeに対して"ほげ"と打つ。 

  3. Q. なんで文字符号のほうがメインで、文字コードが別名みたいな表記なの? A. いや普通文字コードっていったら文字符号化方式さしちゃうじゃろ……