強火で進め

このブログではプログラム関連の記事を中心に書いてます。

JISの第4水準漢字をPythonで処理している時に問題発生

JISの第4水準漢字の先頭の部分、具体的には以下の文字を処理している時に問題が発生&原因判明したのでメモしておきます。

コードポイント 漢字
U+20089 𠂉
U+4E02
U+4E0F
U+4E12
U+4E29
U+4E2B
U+4E2E
U+4E40
U+4E47

これを 𠂉丂丏丒丩丫丮乀乇 と並べた状態で記述されたテキストファイルから文字を読み込んだ時に問題が発生しました。

テキストファイルから1行読み込んだ後に1文字づつに分割しようとlist()を実行した所、以下の様な結果に成りました。

[u'\ud840', u'\udc89', u'\u4e02', u'\u4e0f', u'\u4e12', u'\u4e29', u'\u4e2b', u'\u4e2e', u'\u4e40', u'\u4e47']

解説すると先頭のコードポイントが U+20089 の漢字のみ2つの文字、 u'\ud840' と u'\udc89' に分割されています。それ以降の U+4E02 からはちゃんと1文字づつ分割されているのが確認出来ます。

中々原因が分からなかったのですがこちらのサイトの情報にて原因が判明しました。

uniseg-python
http://www.emptypage.jp/gadgets/uniseg.ja.html

原因部分を引用。

unicode オブジェクト

PythonUnicode 文字列です。

その内部表現は Python インタプリタをビルドした条件によって異なり、narrow と wide とがあります。前者は Unicode 文字列を 16 ビット単位で、後者は 32 ビット単位でメモリに格納しています。

Unicode に収録される文字の数は 16 ビットの範囲を超えています。このため、narrow ビルドでは 16 ビットの範囲外の文字はふたつの 16 ビット表現を組み合わせて表現します(サロゲート・ペア)。

つまり、先頭の U+20089 だけは16bitの範囲を越え、32bitでないと表現出来ないコードポイントで有ったため、分割されたという事だったみたいです。

補足

TwitterにてPython 3.3だとその辺り気にしなくてよくなってるとの情報を頂きました。感謝!!

What’s New In Python 3.3 — Python v3.3.3 documentation
http://docs.python.org/3/whatsnew/3.3.html#pep-393