Python UTF-16 WAVY DASH encoding question / issue
我今天正在做一些工作,遇到一个"看起来很有趣"的问题。 我一直在将某些字符串数据解释为utf-8,并检查了编码形式。 数据来自ldap(特别是Active Directory),是通过python-ldap获得的。 没有惊喜。
因此,我遇到了几次字节序列'\ xe3 \ x80 \ xb0',当解码为utf-8时,它是unicode码点3030(波浪破折号)。 我需要utf-16中的字符串数据,所以自然地我通过.encode('utf-16')进行了转换。 不幸的是,似乎python不喜欢这个字符:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | D:\\> python Python 2.6.4 (r264:75708, Oct 26 2009, 08:23:19) [MSC v.1500 32 bit (Intel)] on win32 Type"help","copyright","credits" or"license" for more information. >>> u"\\u3030" u'\\u3030' >>> u"\\u3030".encode("utf-8") '\\xe3\\x80\\xb0' >>> u"\\u3030".encode("utf-16-le") '00' >>> u"\\u3030".encode("utf-16-be") '00' >>> '\\xe3\\x80\\xb0'.decode('utf-8') u'\\u3030' >>> '\\xe3\\x80\\xb0'.decode('utf-8').encode('utf-16') '\\xff\\xfe00' >>> '\\xe3\\x80\\xb0'.decode('utf-8').encode('utf-16-le').decode('utf-8') u'00' |
看来IronPython也不是粉丝:
1 2 3 4 5 6 7 8 9 | D:\\ipy IronPython 2.6 Beta 2 (2.6.0.20) on .NET 2.0.50727.3053 Type"help","copyright","credits" or"license" for more information. >>> u"\\u3030" u'\\u3030' >>> u"\\u3030".encode('utf-8') u'\\xe3\\x80\\xb0' >>> u"\\u3030".encode('utf-16-le') '00' |
如果有人可以告诉我这里到底发生了什么,将不胜感激。
但是它可以解码:
1 2 3 4 | >>> u"\\u3030".encode("utf-16-le") '00' >>> '00'.decode("utf-16-le") u'\\u3030' |
这是因为该字符的UTF-16编码与" 0"的ASCII码一致。您也可以用'\ x30 \ x30'表示它:
1 2 | >>> '00' == '\\x30\\x30' True |
这似乎是正确的行为。以UTF-16编码时的字符u'\ u3030'与UTF-8中的'00'编码相同。看起来很奇怪,但这是正确的。
您可以看到的'\ xff \ xfe'只是字节顺序标记。
您确定要波浪线而不是其他字符吗?如果您希望使用其他字符,则可能是因为该字符在进入您的应用程序之前已经被错误编码。
您在这里被两件事弄糊涂了(也让我失望):
'00'是字符数字零的两个。它不是空字符。无论如何,打印方式会有所不同:
1 2 | >>> '\\0\\0' '\\x00\\x00' |
上面的示例代码中有一个基本错误。请记住,您将Unicode编码为编码的字符串,然后从编码的字符串解码回Unicode。所以你也是:
1 | '\\xe3\\x80\\xb0'.decode('utf-8').encode('utf-16-le').decode('utf-8') |
转换为以下步骤:
1 2 3 4 | '\\xe3\\x80\\xb0' # (some string) .decode('utf-8') # decode above text as UTF-8 encoded text, giving u'\\u3030' .encode('utf-16-le') # encode u'\\u3030' as UTF-16-LE, i.e. '00' .decode('utf-8') # OOPS! decode using the wrong encoding here! |
u'\ u3030'实际上在UTF-16LE中被编码为'00'(两次ASCII零),但是您不知何故认为这是一个空字节('\ 0')或类似的东西。
请记住,如果使用一个编码并使用另一种编码进行解码,则无法到达相同的字符:
1 2 3 4 5 6 | >>> import unicodedata as ud >>> c= unichr(193) >>> ud.name(c) 'LATIN CAPITAL LETTER A WITH ACUTE' >>> ud.name(c.encode("cp1252").decode("cp1253")) 'GREEK CAPITAL LETTER ALPHA' |
在这段代码中,我编码为Windows-1252,然后从Windows-1253解码。在您的代码中,您编码为UTF-16LE并从UTF-8解码。