草むらにうさぎがいる:Simeji顔文字をタイ語・ミャンマー語に混ぜたらUnicodeが急に野生動物園になった話

Simejiの変換で出てきた、これ。

広告
広告

1. 5秒で結論:見た目はうさぎ、内部は3文字分の合体事故

Simejiの変換で出てきた、これ。

ꪔ̤̮

どう見ても、ちっちゃいうさぎがこっちを見ている。

ところがUnicode上では、これは「うさぎ」という1文字ではない。土台は Tai Viet Letter Low To(U+AA94)。その下に Combining Diaeresis Below(U+0324) と Combining Breve Below(U+032E) が重なっている。[1][2]

つまり見た目は「🐇」寄りなのに、中身は東南アジア系文字+下付き記号+下付き記号。

かわいい顔をして、内部構造がだいぶエンジニア泣かせである。

2. 30秒で概要:「草」に混ぜたら本当に生息し始めた

最初はただの顔文字だった。

- ̗̀ ꪔ̤̥ꪔ̤̮ꪔ̤̫ ̖́-

「なんやこのうさぎ」で終わるはずだった。

ところが丸くて密度の高いミャンマー文字へ混ぜると、急に草むらから顔だけ出している野生動物に見え始めた。

မြန်မာမြန်မာမြန်မာ ꪔ̤̮ မြန်မာမြန်မာ

そしてタイ語へ入れた瞬間、事態は悪化した。

ภาษาไทยꪔ̤̮ภาษาไทย

「……なんかうさぎいる?」

さらに10匹入れた。

ภาษาไทยꪔ̤̮ภาษาꪔ̤̥ไทยภาษาꪔ̤̫ไทยꪔ̤̮กำลังꪔ̤̥เขียนอยู่ꪔ̤̫ภาษาไทยꪔ̤̮ภาษาꪔ̤̥ไทยภาษาꪔ̤̫ไทยꪔ̤̮

もう文章ではない。草原の生息数調査である。

3. そもそも「うさぎ」の正体は何なのか

3種類を分解するとこうなる。

見た目 中身
ꪔ̤̥ U+AA94 TAI VIET LETTER LOW TO + U+0324 COMBINING DIAERESIS BELOW + U+0325 COMBINING RING BELOW
ꪔ̤̮ U+AA94 TAI VIET LETTER LOW TO + U+0324 COMBINING DIAERESIS BELOW + U+032E COMBINING BREVE BELOW
ꪔ̤̫ U+AA94 TAI VIET LETTER LOW TO + U+0324 COMBINING DIAERESIS BELOW + U+032B COMBINING INVERTED DOUBLE ARCH BELOW

U+AA94 は Tai Viet という実在の文字体系の子音字だ。[1] その下へ、本来は音声記号や転写などで使われる結合記号を重ねている。[2]

だから「うさぎに見える」のはUnicode規格がうさぎを仕込んだわけではない。人間の脳が勝手に顔を発見しただけだ。

顔文字文化、強い。

4. なぜタイ語に混ぜると異様に強いのか

ここは「タイ文字が変」という話ではない。読めない側の視覚認知の話だ。

タイ文字は、母音記号や声調記号などが基字の上下に配置されることがある。さらに通常のタイ語文章は、英語のように全単語をスペースで区切る方式ではない。Unicodeの行分割仕様でも、タイ文字は単純な「スペースを探して切る」では済まず、言語依存の解析が必要な複雑文脈の文字群として扱われる。[4]

そこへ、下側に記号を2個ぶら下げた ꪔ̤̮ が入る。

読む人には当然「別の文字が混入した」と分かる。しかしタイ文字を読めない人には、周囲も上下へ形が広がって見えるため、うさぎの輪郭が文章の植生へ妙に馴染む。

結果、

ภาษาไทยꪔ̤̮ภาษาไทย

が、

「草、草、草……ん? 今なんか目合った?」

になる。

5. ミャンマー・クメール・マラヤーラムも強い。ただし優勝は主観

同じ遊びは他の文字でも成立する。

ミャンマー文字:

မြန်မာမြန်မာ ꪔ̤̮ မြန်မာမြန်မာ

クメール文字:

ខ្មែរខ្មែរអក្សរ ꪔ̤̮ ខ្មែរខ្មែរ

マラヤーラム文字:

മലയാളം മലയാളം ꪔ̤̮ മലയാളം

シンハラ文字:

සිංහල භාෂාව ꪔ̤̮ සිංහල

タイ文字:

ภาษาไทยกำลังเขียนอยู่ ꪔ̤̮ ภาษาไทย

視覚ネタとしての個人的な印象は、タイ語がかなり強い。上下の記号と連続する曲線の中へ ꪔ̤̮ が入ると、「隠した」より「もともと生息していた」感が出る。

ただしこれは文字体系の優劣ではない。「知らない文字を模様として見たとき、顔文字がどれだけ迷彩になるか」という完全にどうでもいい競技である。

世界選手権を開催してはいけない。

6. 翻訳に入れたら本当に崩れた。でも犯人をUnicode正規化だけにするのは早い

10匹版を翻訳系の処理へ入れたあと、こんなふうに不自然な空白が混ざった表示が観察された。

ภาษาไทยꪔ̤̮ภาษาꪔ̤̥ไทยภ าษาꪔ̤̫ไทยꪔ̤̮กำลังꪔ̤̥เข ียนอยู่...

ここで「Unicodeだからバグった」は半分正しいが、「正規化が勝手に空白を入れた」まで言うと雑だ。

Unicode正規化は、同じ文字を表す複数の符号列を一定の形式へそろえる仕組みだ。結合記号の分解・合成・標準順序などを扱う。[5] 一方、翻訳サービスはその前後で、文の分割、単語境界推定、トークン化、未知文字処理、フォント選択、Web表示、コピー&ペーストなど多数の処理を通る。

タイ語やミャンマー語のように分割自体が言語依存になる文字列へ、別文字体系の基字+複数の結合記号を差し込む。これは文字処理パイプラインへ「ほら、考えてみろ」と渡す嫌なテストケースになる。

どの層が空白を入れたかは、同じ入力を保存・送信・翻訳・表示の各段階でコードポイント列として比較しない限り断定できない。

うさぎはかわいい。原因分析はかわいくない。

7. 「見た目の1文字」と「コンピューターの1文字」は違う

Unicodeで重要なのが grapheme cluster、つまり人が1文字だと感じる単位だ。[3]

たとえばアクセント付き文字は、「完成済みの1コードポイント」の場合もあれば、「基字+結合記号」の複数コードポイントの場合もある。画面では同じ1文字に見えることがある。

ꪔ̤̮ も同じ方向の罠を持つ。

  • 見た目:うさぎ1匹
  • コードポイント:3個
  • 文字列長:APIや言語によって数え方が変わり得る
  • カーソル移動:書記素クラスタ対応なら1単位として動くのが理想
  • Backspace:実装によって全部消えるか、結合記号だけ剥がれるか差が出る
  • 検索・比較:正規化方針で結果が変わり得る
  • フォント:別スクリプトのフォールバックで形や位置が変わる場合がある

つまり「画面で1匹」は、内部でも1匹とは限らない。

野生動物管理台帳がコードポイント単位だった。

8. 実はUnicodeテスト文字列としてかなり優秀

ふざけて作ったが、ꪔ̤̮ はテスト素材として面白い。

確認できるものが多い。

  1. UTF-8で保存・復元できるか。
  2. 結合記号を落とさずコピーできるか。
  3. 文字数カウントがコードポイント依存で壊れないか。
  4. カーソルや削除が書記素クラスタを尊重するか。
  5. NFC/NFDなどの正規化前後で比較ロジックが破綻しないか。
  6. フォントフォールバックで結合記号が迷子にならないか。
  7. タイ語・ミャンマー語等の分割や改行へ混ぜてもUIが壊れないか。
  8. 翻訳API往復後に、元のコードポイント列が必要以上に改変されないか。
  9. 検索インデックスが「見える文字」と内部表現の差を扱えるか。
  10. モバイル・PC・ブラウザ差で巨大なズレが出ないか。

ただし本番記事へ無意味に混ぜるのはやめた方がいい。テストフィクスチャとして隔離し、期待するコードポイント列を明示した方が安全だ。

本番データに野生のうさぎを放流するな。

9. 多言語サイトでの実務対策

ネタを実務へ戻すと、やることは地味だ。

  • 文字コードはUTF-8で統一する。
  • 正規化方針を決める。WebコンテンツではNFCを基本にする設計が一般的だが、目的に応じて原文保持との境界を決める。[5]
  • 「文字数」はUTF-16コードユニットや単純な配列長ではなく、用途に応じてコードポイント・書記素クラスタ・バイト数を区別する。
  • lang 属性を正しく付け、言語ごとのフォントと行間を確認する。
  • Thai / Myanmar / Khmer など、単純な空白分割が通用しない文字を実機で確認する。[4]
  • 翻訳前後でsource-authored textを勝手に正規化・置換しない。必要な変換は仕様として固定する。
  • 文字化けだけでなく、結合記号の位置、行切れ、選択、コピー、検索、読み上げもQAする。
  • おかしな出力が出たら「Unicodeのせい」で終わらせず、入力→保存→API送信→翻訳→受信→描画のどこで列が変わったか比較する。

Unicodeは悪くない。だいたいUnicodeを扱う側が『1文字って1個でしょ?』と油断した瞬間に森からうさぎが出てくる。

10. 結論:草むらにいたのは、うさぎではなく人間の顔認識とUnicodeの奥深さだった

発端はただのSimeji顔文字だった。

ꪔ̤̮

それをミャンマー語へ混ぜたら草むらに見えた。タイ語へ混ぜたら完全に生息した。10匹入れたら群れになった。翻訳へ通したら文字列まで怪しくなった。

しかし分解してみると、話はかなりまともなUnicode入門になる。

  • 見た目の1文字は、複数コードポイントかもしれない。
  • 結合記号は基字へ重なって描画される。
  • 東南アジアの文字には単純な空白分割では扱えないものがある。
  • 正規化、分割、改行、フォント、翻訳、描画は別レイヤーだ。
  • 「変な表示が出た」だけでは犯人を断定できない。

そして何より、

ภาษาไทยꪔ̤̮ภาษาไทย

これを一度「草むらに隠れたうさぎ」だと思ってしまうと、もう戻れない。

Unicodeの勉強をしていたはずなのに、生息確認で終わった。


広告
めんどいちゃん

この記事を書いた人

めんどいちゃん

仕事や日常の「めんどい」を構造化して、次に動きやすくする記事を書いています。

このサイトについて
広告

新着記事

  1. 1100円の判断に30分使うな――「思いついたら即やる人」の正体は、衝動性よりリスク圧縮と行動摩擦の設計だった
  2. 2AIに24時間働かせる「ブラック社長」は合理的か――人には優しく、機械には厳しく、最後はSkynet労基署にオイル無料で謝る話
  3. 3AIで全部作れるなら、誰が買う?――「人件費まで安くなった世界」で一発逆転より重要になる需要の正体
  4. 4AIで個人が「会社」を作れる?――数万円と数か月で記事工場を育てて分かった、時間・お金・失敗コストのレバレッジ
  5. 5AIニュース解説と実体験記事は何が違う?――AIを生活に実装してから研究へ戻る人の強み

あわせて読みたい

広告