はじめに
元ネタ: Javaで湯婆婆を実装してみる - Qiita
これをPythonで実装してみた前回の記事: Python 3で湯婆婆を実装してみる - Qiita
お前は湯婆婆で何本書く気なのか。
湯婆婆のもとにはいろんな人が働かせてもらいに来ますが、ある名前の人が来ると湯婆婆が崩壊するかもしれないと心配していました。実際に調べてみたら大丈夫だったという話です。今回は空文字列 "" は無しです
コード
前回の記事の再掲です。Python 3.6以降に対応。
import sys
import random
print("契約書だよ。そこに名前を書きな。")
name = sys.stdin.readline().rstrip()
print(f"フン。{name}というのかい。贅沢な名だねぇ。")
newName = random.choice(name)
print(f"今からお前の名前は{newName}だ。いいかい、{newName}だよ。分かったら返事をするんだ、{newName}!!")
「𠮷田」さんがやってきた
湯婆婆を訪ねた「𠮷田」さんの**「𠮷」の字は「土」の下に「口」と書く、いわゆる「つちよし」です。**「𠮷野家」の「𠮷」であり「𠮷澤ひとみ」の「𠮷」でもあります。
Windowsのコマンドプロンプトだと入力時点で崩壊するので、LinuxやCygwin環境で実行してください。
$ python3 yubaba.py
契約書だよ。そこに名前を書きな。
𠮷田
フン。𠮷田というのかい。贅沢な名だねぇ。
今からお前の名前は𠮷だ。いいかい、𠮷だよ。分かったら返事をするんだ、𠮷!!
無事に「𠮷」と呼んでもらえたら成功です。
一方、もしかするとこうなってしまった方もいるかもしれません。おそらくいないと思います(後述)。
契約書だよ。そこに名前を書きな。
𠮷田
フン。𠮷田というのかい。贅沢な名だねぇ。
今からお前の名前は▒だ。いいかい、▒だよ。分かったら返事をするんだ、▒!!
𠮷田さんにまともな名前をつけてあげてください。
サロゲートペア
「𠮷」の字は16ビットのコード1つでは表現できません。16ビットのコードを使って表すときは2つ組み合わせることになります。これをサロゲートペアと呼びます。
Python湯婆婆が𠮷田さんにまともな名前をつけられるかどうかは、Python内部で1文字を何ビットで表現しているかによって決まります。
sys — System-specific parameters and functions — Python 3.9.0 documentation
import sys
print(sys.maxunicode)
1114111
65535 より大きい値が出たら、文字列の内部表現はUCS-4 (32ビット) です。このとき、湯婆婆は𠮷田さんを無事に受け入れることができます。「𠮷」を正しく1文字として認識しているからです。
import sys
print(sys.maxunicode)
65535
65535 ならば、文字列の内部表現はUCS-2 (16ビット) です。この場合、残念ながら湯婆婆は𠮷田さんの訪問を想定していません(偶然「田」と命名されれば問題ないのですが)。「𠮷」は本来1文字なのに、内部では16ビットの文字2個として扱われます。2個並びの片方だけをとっても意味をなさないため、文字化けしてしまいます。
関連: UCS-2 か UCS-4 かによって len や unichr の戻り値が変わることがある - Qiita
Python 3.3以降では問題なくサポートされる
実のところ、Python 3.3以降では常にUCS-4が使われるようになったそうなので、「𠮷田」さんに悩む必要はありません。
What's New In Python 3.3 — Python 3.9.0 ドキュメント
Python は今や非 BMP 面の文字を含む Unicode コードポイントの完全な範囲 (つまり U+0000 から U+10FFFF まで) を常にサポートします。narrow ビルド / wide ビルドという区別は今では存在していないため、Python は今ではいつでもかつての wide ビルドのように振る舞い、Windows でもこれは例外ではありません。
Python 2.xのときは、UCS-2でビルドされることも多かったので、「𠮷田」さんが来るとバグる湯婆婆がいたと思われます。もうサポート期限切れなので良いですよね。
configureのオプションが命運を握っていた (Python 2の時代)
Python 2をソースコードからビルドする場合には、configureのオプションとして --enable-unicode=ucs4
をつけることで、内部表現をUCS-4にすることができます(した)。
パッケージマネージャでインストールするとUCS-4版になっていることも多いですが、もしUCS-2版のPythonだったら、上記オプションをつけてソースコードからビルドすることにより解決できます。
関連: unicode - How to find out if Python is compiled with UCS-2 or UCS-4? - Stack Overflow
最後に
Python 3なら「髙田」さんも「山﨑」さんも「草彅」さんもどんと来い。