30歳からのプログラミング

30歳無職から独学でプログラミングを開始した人間の記録。

Unicode における置換文字(replacement character)について

この記事では、 Unicode において表示不可能な文字を表現する「置換文字」について説明する。

この記事に出てくるコードの動作確認は以下の環境で行った。

  • Deno 1.26.0
  • TypeScript 4.8.3

概要

Unicode において、表示しようとした文字が何らかの理由で表示不可能なとき、黒い菱形に白いクエスチョンマークが書かれた文字が表示される。
「�」がそうなのだが、環境によっては表示されずカギカッコの中が空白になっているかもしれないので、画像も載せておく。

この文字を「置換文字」と呼ぶ。

サロゲートペアとして不正なケース

文字が表示不可能な例として、サロゲートペアとして正しくないケースがある。

サロゲートペアや Code Point の概要は以前書いたので、必要ならこちらを読んで欲しい。
numb86-tech.hatenablog.com

Code Point のうち一部分はサロゲートペアに使うものとして予め定められており、単独で文字を表現することはない。
具体的にはU+D800からのU+DFFFの 2048 文字分がそれに該当する。
これらの Code Point は代用符号位置と呼ばれる。
さらに、代用符号位置は前半(U+D800U+DBFF)と後半(U+DC00U+DFFF)に分かれており、前半を上位サロゲート、後半を下位サロゲートとして使うことも決まっている。

上記のルールに反した場合、無効なデータと見做され置換文字が表示される。

// 単独の代用符号位置で文字を表現することはできない
console.log(`\u{d800}`); // �

// dc00 が上位サロゲートに来ることはないし、 d800 が下位サロゲートに来ることもない
console.log(`\udc00\ud800`); // ��

置換文字の Code Point や Code Unit について

表示不可能な文字は全てとして表示しようというだけの話なので、表示結果が同じだったとしても、 Code Point や Code Unit が異なれば、それは別の文字である。

const x = `\udc00`;
const y = `\udc01`;
const z = `\udc02`;

// 三文字とも � と表示されるが……
console.log(x, y, z); // � � �

// 全て別々の文字である
console.log(x === y); // false
console.log(x === z); // false
console.log(y === z); // false

ちなみに、そのものの Code Point はU+FFFDである。

console.log("�".codePointAt(0)?.toString(16)); // fffd