2013-08-28 63 views
0

(Python 3.3.2)我不得不通過調用re.escape()返回一些非ASCII轉義字符。我看到herehere方法不起作用。我正在使用100%UTF-8環境。Python3:未修改非ascii字符

# pure ASCII string : ok 
mystring = "a\n" # expected unescaped string : "a\n" 
cod = codecs.getencoder('unicode_escape') 
print(cod(mystring)) 

# non ASCII string : method #1 
mystring = "€\n" 
# equivalent to : mystring = codecs.unicode_escape_decode(mystring) 
cod = codecs.getdecoder('unicode_escape') 
print(cod(mystring)) 
# RESULT = ('â\x82¬\n', 5) INSTEAD OF ("€\n", 2) 

# non ASCII string : method #2 
mystring = "€\n" 
mystring = bytes(mystring, 'utf-8').decode('unicode_escape') 
print(mystring) 
# RESULT = â\202¬ INSTEAD OF "€\n" 

這是一個錯誤?我誤解了一些東西嗎?

任何幫助,將不勝感激!

PS:我編輯我的帖子感謝Michael Foukarakis的評論。

+0

你在哪裏執行在終端/ CMD或文件? – badc0re

+0

'「€\\ n」'不是一個Unicode轉義字符串,所以你不能將它解碼爲任何有意義的東西。 ''\ n「',如果它被Unicode轉義了,就會變成'b'\\ u20ac \\ n''。所以,你好像誤解了編碼。 –

+0

好點:我編輯了我的帖子。但是我的問題與(unicode)字符相同。 – suizokukan

回答

1

您似乎誤解了編碼。要針對常見錯誤進行保護,我們通常編碼字符串,當它離開我們的應用程序,當談到在其解碼

首先,讓我們來看看文檔unicode_escape,其中規定:

農產品[s]適合作爲Python源代碼中的Unicode字面值的字符串。

這裏是你會從網絡或聲稱文件獲取其內容的Unicode的轉義:

b'\\u20ac\\n' 

現在,你要解碼這在您的應用程序中使用它:

>>> s = b'\\u20ac\\n'.decode('unicode_escape') 
>>> s 
'€\n' 

,如果你想把它寫回,比方說,一個Python源文件:

with open('/tmp/foo', 'wb') as fh: # binary mode 
    fh.write(b'print("' + s.encode('unicode_escape') + b'")') 
+0

謝謝你的回答。我的「編碼」字符串(例如「\€\ n」)具有非常的Pythonic起源:它是通過調用re.escape()返回的值。據我所知,沒有反函數,如re.unescape()。因此我嘗試解碼「轉義」字符串。我怎樣才能做到這一點? – suizokukan

+0

問題的答案是「哪個是合適的編碼?」取決於它將如何使用。那麼,你的用例是什麼?另外,你確定're.escape'是必要的,也就是說你使用用戶輸入作爲正則表達式嗎? –

+0

這些字符串是從UTF-8編碼的文件中讀取的,並且將作爲UTF-8字符串寫入另一個文件中。幸運的是,我不會混用不同的編碼。 – suizokukan

0
import string 
printable = string.printable 
printable = printable + '€' 

def cod(c): 
    return c.encode('unicode_escape').decode('ascii') 

def unescape(s): 
    return ''.join(c if ord(c)>=32 and c in printable else cod(c) for c in s) 

mystring = "€\n" 
print(unescape(mystring)) 

不幸的是string.printable只包含ASCII字符。您可以像我這樣做一個副本,並用任何您想要的Unicode字符擴展它,例如

1

我猜你需要處理的實際字符串是mystring = €\\n

mystring = "€\n" # that's 2 char, "€" and new line 
mystring = "€\\n" # that's 3 char, "€", "\" and "n" 

我真的不明白髮生了什麼錯誤內encode()和python3的decode(),但是當我們正在編寫一些工具我的朋友解決了這個問題。

我們是如何做到的旁路encoder("utf_8")逃逸程序完成後。

>>> "€\\n".encode("utf_8") 
b'\xe2\x82\xac\\n' 
>>> "€\\n".encode("utf_8").decode("unicode_escape") 
'â\x82¬\n' 
>>> "€\\n".encode("utf_8").decode("unicode_escape").encode("utf_8") 
b'\xc3\xa2\xc2\x82\xc2\xac\n' # we don't want this 
>>> bytes([ord(char) for char in "€\\n".encode("utf_8").decode("unicode_escape")]) 
b'\xe2\x82\xac\n' # what we really need 
>>> str(bytes([ord(char) for char in "€\\n".encode("utf_8").decode("unicode_escape")]), "utf_8") 
'€\n' 

我們可以看到:雖然的decode("unicode_escape")結果看起來有線的bytes對象實際上包含你的字符串的正確字節(使用UTF-8編碼),在這種情況下,"\xe2\x82\xac\n"

我們現在不直接打印str對象,我們也不使用encode("utf_8"),我們使用ord()創建bytes對象b'\xe2\x82\xac\n'

而且你可以從這個bytes對象正確str,只是把它變成str()


BTW,工具我的朋友,我想提出的是一個包裝,允許用戶輸入類似C字符串文字,並自動轉換轉義序列。

User input:\n\x61\x62\n\x20\x21 # 20 characters, which present 6 chars semantically 
output: # \n 
ab  # \x61\x62\n 
!  # \x20\x21 

這是一個強大的工具,用戶可以在終端輸入一些不可打印的字符。

我們最終的工具是:

#!/usr/bin/env python3 
import sys 

for line in sys.stdin: 
    sys.stdout.buffer.write(bytes([ord(char) for char in line[:-1].encode().decode('unicode_escape')])) 
    sys.stdout.flush()