2017-12-13 25 views
3

正規化後も2つのUnicode文字列があります。しかし、UTF-8にコード化されている場合、それらは同じです。私は彼らがどう違うのか(そしておそらくなぜ)理解したいと思います。異なるUnicode文字列が同じものを符号化する

これらはどちらもエンティティの識別子であり、識別子が間違っているためにルックアップに失敗しますが、バイト文字列は同じなので、どのように異なるUnicode文字列に到着した可能性があるか理解したいと思います異なるサブシステムで処理されている)と、実際に同じであることをどのように伝えることができるかを示します。

"\u8a92\u6089\u5bfd\u4267\ucdb7\u5727\u4039\U0002ae18\U00025314\u30c3"

と:

"\u8a92\u6089\u5bfd\u4267\ucdb7\u5727\u4039\ud86b\ude18\ud854\udf14\u30c3"

問題は、正規ではありません。私はこの質問の要素は答えられないことを認識していますが、私は手がかりを感謝するでしょう!

>>> a = u"\u8a92\u6089\u5bfd\u4267\ucdb7\u5727\u4039\ud86b\ude18\ud854\udf14\u30c3" 
>>> b = u"\u8a92\u6089\u5bfd\u4267\ucdb7\u5727\u4039\U0002ae18\U00025314\u30c3" 
>>> a == b 
False 
>>> import unicodedata 
>>> unicodedata.normalize('NFKD', a) == unicodedata.normalize('NFKD', b) 
False 
>>> a.encode('UTF-8') == b.encode('UTF-8') 
True 
+6

文字U + D86Bや友人がサロゲート文字である、すなわち。 (実際の)コードポイントをU + FFFFよりも上に符号化するためにUTF16によって使用される(偽の)コードポイントです。文字列 'a'は正しくデコードされていません。 @ snakecharmerbが指摘しているように、最近のPythonのバージョンでは、この文字列は壊れていると見なされます。 Python 2.7ではこれが許されているようです。 – lenz

答えて

0

あなたの結果がどのようになっているのかわかりません。 Pythonの2.7で、あなたのab Unicode文字列は同じです:

>>> a = u"\u8a92\u6089\u5bfd\u4267\ucdb7\u5727\u4039\ud86b\ude18\ud854\udf14\u30c3" 
    >>> b = u"\u8a92\u6089\u5bfd\u4267\ucdb7\u5727\u4039\U0002ae18\U00025314\u30c3" 
    >>> a == b 
    True 
    >>> a 
    u'\u8a92\u6089\u5bfd\u4267\ucdb7\u5727\u4039\U0002ae18\U00025314\u30c3' 
    >>> b 
    u'\u8a92\u6089\u5bfd\u4267\ucdb7\u5727\u4039\U0002ae18\U00025314\u30c3' 

のPython 2.7は、Unicode文字列を格納するために内部的にUTF-16LEを使用しています。 U + FFFFを超えるコードポイントは、サロゲート(2つの16ビットコードユニット)を使用して格納されます。別々に入力しても同じように表示されることに注意してください。 2つの文字列は、内部的に解析され、同じ方法で保存されます。別の例:Pythonで

>>> s = u'\U00025314' 
>>> len(s) 
2 
>>> hex(ord(s[0])) 
'0xd854' 
>>> hex(ord(s[1])) 
'0xdf14' 
>>> s = u'\ud854\udf14' 
>>> s 
u'\U00025314' 

3.3+のUnicodeを内部に格納されているかのleaky abstractionさらす実装の詳細が修正されました:

>>> # python 3.3+ 
>>> s = '\U00025314' 
>>> len(s) 
1 
>>> hex(ord(s[0])) 
>>> hex(ord(s[0])) 
'0x25314' 
>>> s.encode('utf8') 
b'\xf0\xa5\x8c\x94' 

>>> s = '\ud854\udf14' 
>>> s 
'\ud854\udf14' 
>>> s.encode('utf8') 
Traceback (most recent call last): 
    File "<interactive input>", line 1, in <module> 
UnicodeEncodeError: 'utf-8' codec can't encode characters in position 0-1: surrogates not allowed 
関連する問題