にせねこメモ

はてなダイアリーがUTF-8じゃないので移ってきました。

Twitterで旧字が化ける? CJK互換漢字という罠

概要

Twitterに投稿するとCJK互換漢字が対応する統合漢字に化けるので、投稿時に化けないStandard Variant形式と互換漢字とを相互変換するページを作成した: 互換漢字-異体字セレクタ コンバータ

はじめに

Twitterで「社」(U+FA4C)、「羽」(U+FA1E)などの一部の旧漢字を投稿しようとすると、「社」(U+793E)、「羽」(U+7FBD)に化ける。

Twitterに次の文字列を投稿すると

神(U+FA19)と神(U+795E)
福(U+FA1B)と福(U+798F)
羽(U+FA1E)と羽(U+7FBD)
既(U+FA42)と既(U+65E2)
梅(U+FA44)と梅(U+6885)
社(U+FA4C)と社(U+793E)
練(U+FA57)と練(U+7DF4)
者(U+FA5B)と者(U+8005)

こうなる:


左側の字が右側の字と同じになっている。


これは一体どういうことなのだろうか? 実は、Unicodeの問題である。

CJK互換漢字

これらの化ける文字は、UnicodeにおいてCJK互換漢字という領域に収録されている。互換漢字に対し、基本となる漢字はCJK統合漢字と呼ばれる。CJKはChina, Japan, Koreaの略で、各国で微妙に字体が違っても、同一とされた*1漢字は国に関わらず一つとし、原則として重複収録はしない方針となっている。
しかし、CJK互換漢字は名前の通り、互換性を保つために収録された漢字である。それまでの文字コード等との互換性を保つ関係*2で「同じ文字を重複して収録した」扱いであり、CJK統合漢字の中に対応する漢字をもつ。

Unicode正規化

ここで、Unicodeは検索等の利便性のために、「Unicode正規化(normalization)」という処理を提供している。これは、記号付きのアルファベットなど、二種類以上のコード列で表すことができる文字列を適切に比較したりするために重要な処理である。しかし、CJK互換漢字に対してUnicode正規化を行うと、対応するCJK統合漢字に「化けて」しまう*3

Twitter投稿時のUnicode正規化

Twitterは、2015年から投稿時にUnicode正規化を行うようになった*4。そのため、CJK互換漢字をTwitterに投稿すると対応するCJK統合漢字に置換されてしまい、CJK互換漢字を投稿することはできなくなった。

Standardized Variant

とはいっても、Unicode正規化によってCJK互換漢字が化けてしまうと困る。そういった場合のために、Unicode異体字セレクタという仕組みを使ってCJK互換漢字相当の漢字を表現できる枠組みが作られた(2013年9月制定のUnicode 6.3)。これによって表現されたものをStandardized Variantとよぶ。これは、Unicode Character DatabaseのStandardizedVariants.txtの後半に定義されている。
この仕組みを使うと、Unicode正規化を行っても化けないため、Twitter等にCJK互換漢字の字形の漢字を投稿することができる(ただし、正しい形で表示されるかは環境による)。

互換漢字↔Standardized Variant変換器

CJK互換漢字はともかく、Standardized Variant形式を入力することは不便なので、CJK互換漢字とStandardized Variant形式を相互に変換するページを作成した。

TwitterにCJK互換漢字に含まれる字形を投稿したい場合等に利用していただきたい。

Standardized Variantの実際の表示


Standardized Variantで表現されたものは、環境によるが互換漢字の字形で表示される。手元のWindows 10環境では、Firefoxでは互換漢字の字形で表示されたが、Chromeではそうはならなかった。
f:id:nixeneko:20190316185449p:plain
Firefoxで見たStandardized VariantによるTwitter投稿結果
(20190318追記)これを正しく互換漢字の字形で表示するためにはフォントが対応している必要がある*5Chrome等では対応フォント以外で表示すると互換漢字の形で表示できない。(6.0 Marshmallow以降の)Androidのデフォルトフォントである源ノ角ゴシックは対応しているので、Androidでは正しく互換漢字の字形で表示される。一方、Firefoxは独自に互換漢字の字形で表示するような実装をしている可能性があり、フォントによらず表示できるようだ。Standardized Variant (というより異体字セレクタ)を使った投稿をする場合は、このようにフォントやソフトウェアの対応が微妙であり、必ずしも狙った形で表示されないことに留意する必要がある。(追記終)

ちなみに、ちゃんと変換できているかなどは、

などのページで確認できる。

*1:細かい字体の違いを無視し同一とみなすことを包摂(unification)という。

*2:「ラウンドトリップ変換(round-trip conversion)の確保」といい、既存の文字コード(Shift_JISなど)からUnicodeに変換し、その後元の文字コードに再度変換したときに、内容(文字コード列)が同一になるように保証されている。

*3:Unicode正規化における等価性は正準等価と互換等価という2種類がある(Unicodeの等価性 - Wikipedia)のだが、CJK互換漢字については正準等価となっている。正準等価は見た目も機能としても同じものに対して適用されるべきものなので、互換漢字という見た目が異なるものに対して適用されているので問題となっている。Unicode正規化には種類があり、互換等価については対象としないものもあるが、正準等価は常に対象になる。

*4:厳密な時期はこちらで推定されている: TwitterにUnicode正規化が導入された時刻の推定 by zeeksphere - Togetter

*5:https://twitter.com/monokano/status/1106927404579061761