2010-02-15 92 views
4

我今天做了一些工作,遇到了一個「看起來很有趣」的問題。我一直在解釋一些字符串數據爲utf-8,並檢查編碼後的表單。數據來自ldap(特別是Active Directory),通過python-ldap。那裏沒有驚喜。Python UTF-16 WAVY DASH編碼問題

所以我在字節序列'\ xe3 \ x80 \ xb0'幾次,當解碼爲utf-8時,它是unicode codepoint 3030(wavy dash)。我需要utf-16中的字符串數據,所以自然我通過.encode('utf-16')轉換它。不幸的是,它似乎Python不喜歡這個角色:

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的是不是一個球迷之一:

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' 

如果有人能告訴我,究竟是什麼,是怎麼回事,它會非常感激。

+0

很好問的問題...與預期的人物形象的鏈接是一個很好的接觸。 – 2010-02-15 21:53:22

+0

使用UTF-16對某些內容進行編碼,然後使用UTF-8進行解碼不太可能產生明智的結果。充其量 - 如果輸入是ASCII編碼 - 你會得到一個明智的人物,每秒鐘一次:) – 2010-02-15 22:09:49

+0

是的,最後一行是一個混淆我很大的錯誤。謝謝。 – NoName 2010-02-15 22:19:48

回答

2

這似乎是正確的行爲。以UTF-16編碼時的字符u'\ u3030'與UTF-8中的'00'的編碼相同。這看起來很奇怪,但它是正確的。

你可以看到'\ xff \ xfe'只是一個Byte Order Mark

你確定你想要一個波浪短跑,而不是其他角色嗎?如果您希望獲得不同的角色,那麼可能是因爲它在進入您的應用程序之前已經被錯誤編碼。

+0

好吧,它來自一個名爲userParameters的幾乎沒有記錄的AD屬性,我注意到它的原因是該字段同時具有0x00和'\ xe3 \ x80 \ xb0'組合(實際上彼此靠近)。我想這可能是微軟不能正確編碼的東西。 – NoName 2010-02-15 22:01:44

+0

如果你把它寫成''\ x30 \ x30''而不是'00',它可能會更清楚嗎?不同的符號,相同的字符串。 – 2010-02-15 22:03:16

+0

@NoName:可能他們使用\ x00作爲分隔符 - 我對協議不熟悉,所以這只是一個猜測。假設它不是敏感信息,你可能想在這裏發佈整個字符串,因爲它可能會給我們更多的提示。 – 2010-02-15 22:09:59

2

但解碼沒關係:

>>> u"\u3030".encode("utf-16-le") 
'00' 
>>> '00'.decode("utf-16-le") 
u'\u3030' 

這是該字符的UTF-16編碼恰好與「0」的ASCII碼一致。你也可以用 '\ X30 \ X30' 代表它:

>>> '00' == '\x30\x30' 
True 
1

您正在這裏兩件事情混爲一談(扔我太):

  1. UTF-16和UTF-32編碼使用除非您通過utf-16-be等指定要使用的字節順序。這是最後一行中的\ xff \ xfe。
  2. '00'是digit zero中的兩個字符。它不是空字符。那會不同反正打印:

    >>> '\0\0' 
    '\x00\x00' 
    
0

。在你的示例代碼中一個基本的錯誤之上。記住,你編碼到Unicode編碼的字符串的,你從解碼編碼字符串回爲Unicode。所以,你這樣做:

'\xe3\x80\xb0'.decode('utf-8').encode('utf-16-le').decode('utf-8') 

它轉換爲以下步驟:在UTF-16LE,但你

'\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' 的確是編碼爲 '00'(ASCII零兩次)不知何故認爲這是一個空字節('\ 0')或什麼的。

記住,如果你有一個編碼不能達到相同的字符,並用另一種編碼解碼:

>>> 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解碼。