2017-12-13 6 views
3

Ich habe zwei Unicode-Strings, die auch nach der Normalisierung unterschiedlich sind. Wenn sie jedoch in UTF-8 codiert sind, sind sie identisch. Ich würde gerne verstehen, wie (und vielleicht warum) sie anders sind.Verschiedene Unicode-Strings kodieren die gleichen

Sie sind beide Bezeichner für Entitäten und die Suche schlägt fehl, weil der Bezeichner falsch ist, aber als Bytefolgen sind sie gleich, also würde ich gerne verstehen, wie es möglich ist, dass wir bei verschiedenen Unicode-Strings angekommen sind von verschiedenen Subsystemen verarbeitet) und wie ich feststellen konnte, dass sie tatsächlich gleich sind.

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

und:

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

Das Problem scheint nicht Normalisierung zu sein. Ich erkenne, dass Elemente dieser Frage unbeantwortbar sind, aber ich würde alle Hinweise schätzen!

>>> 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

Die Zeichen U + D86B und Freunde sind Ersatzzeichen, dh. (falsche) Codepoints, die von UTF16 verwendet werden, um (tatsächliche) Codepunkte über U + FFFF zu codieren. String 'a' wurde somit nicht richtig dekodiert. Wie @snakecharmerb angemerkt hat, sehen neuere Python-Versionen diese Zeichenfolge als defekt an; Python 2.7 scheint dies jedoch zu erlauben. – lenz

Antwort

0

Ich bin nicht sicher, wie Sie Ihr Ergebnis erhalten. In Python 2.7, Ihre a und b Unicode-Strings sind die gleichen:

>>> 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 verwendet UTF-16LE intern Unicode-Strings zu speichern. Codepunkte über U + FFFF werden unter Verwendung von Ersatzzeichen (zwei 16-Bit-Code-Einheiten) gespeichert. Beachten Sie, dass sie dasselbe anzeigen, obwohl sie anders eingegeben wurden. Die beiden Strings werden analysiert und intern auf die gleiche Weise gespeichert. Ein weiteres Beispiel:

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

In Python 3.3+ die leaky abstraction Belichtungsimplementierungsdetails wie Unicode intern gespeichert ist, wurde behoben:

>>> # 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 
Verwandte Themen