[英]how do I .decode('string-escape') in Python3?
我有一些需要轉義的轉義字符串。 我想在 Python 中做到這一點。
例如,在 python2.7 中,我可以這樣做:
>>> "\\123omething special".decode('string-escape')
'Something special'
>>>
我如何在 Python3 中做到這一點? 這不起作用:
>>> b"\\123omething special".decode('string-escape')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
LookupError: unknown encoding: string-escape
>>>
我的目標是成為 abel 接受這樣的字符串:
s\000u\000p\000p\000o\000r\000t\000@\000p\000s\000i\000l\000o\000c\000.\000c\000o\000m\000
並將其變成:
"support@psiloc.com"
完成轉換后,我將探查我擁有的字符串是用 UTF-8 還是 UTF-16 編碼的。
您必須改用unicode_escape
:
>>> b"\\123omething special".decode('unicode_escape')
如果您從str
對象開始(相當於 python 2.7 unicode),您需要先編碼為字節,然后使用unicode_escape
解碼。
如果您需要字節作為最終結果,則必須再次編碼為合適的編碼( .encode('latin1')
,如果您需要保留文字字節值;前 256 個 Unicode 代碼點映射 1-on- 1)。
您的示例實際上是帶有轉義符的 UTF-16 數據。 從unicode_escape
解碼,回到latin1
以保留字節,然后從utf-16-le
(UTF 16 little endian without BOM):
>>> value = b's\\000u\\000p\\000p\\000o\\000r\\000t\\000@\\000p\\000s\\000i\\000l\\000o\\000c\\000.\\000c\\000o\\000m\\000'
>>> value.decode('unicode_escape').encode('latin1') # convert to bytes
b's\x00u\x00p\x00p\x00o\x00r\x00t\x00@\x00p\x00s\x00i\x00l\x00o\x00c\x00.\x00c\x00o\x00m\x00'
>>> _.decode('utf-16-le') # decode from UTF-16-LE
'support@psiloc.com'
舊的“字符串轉義”編解碼器將字節串映射到字節串,關於如何處理此類編解碼器存在很多爭論,因此目前無法通過標准編碼/解碼接口使用它。
但是,代碼仍然存在於 C-API 中(作為PyBytes_En/DecodeEscape
),並且它仍然通過未記錄的codecs.escape_encode
和codecs.escape_decode
暴露給 Python。
>>> import codecs
>>> codecs.escape_decode(b"ab\\xff")
(b'ab\xff', 6)
>>> codecs.escape_encode(b"ab\xff")
(b'ab\\xff', 3)
這些函數返回轉換后的bytes
對象,加上一個表示處理了多少字節的數字……你可以忽略后者。
>>> value = b's\\000u\\000p\\000p\\000o\\000r\\000t\\000@\\000p\\000s\\000i\\000l\\000o\\000c\\000.\\000c\\000o\\000m\\000'
>>> codecs.escape_decode(value)[0]
b's\x00u\x00p\x00p\x00o\x00r\x00t\x00@\x00p\x00s\x00i\x00l\x00o\x00c\x00.\x00c\x00o\x00m\x00'
如果你想str -to- str解碼轉義序列,那么輸入和輸出都是 Unicode:
def string_escape(s, encoding='utf-8'):
return (s.encode('latin1') # To bytes, required by 'unicode-escape'
.decode('unicode-escape') # Perform the actual octal-escaping decode
.encode('latin1') # 1:1 mapping back to bytes
.decode(encoding)) # Decode original encoding
測試:
>>> string_escape('\\123omething special')
'Something special'
>>> string_escape(r's\000u\000p\000p\000o\000r\000t\000@'
r'\000p\000s\000i\000l\000o\000c\000.\000c\000o\000m\000',
'utf-16-le')
'support@psiloc.com'
你不能在字節字符串上使用unicode_escape
(或者更確切地說,你可以,但它並不總是像string_escape
在 Python 2 上那樣返回相同的東西)——當心!
此函數使用正則表達式和自定義替換邏輯實現string_escape
。
def unescape(text):
regex = re.compile(b'\\\\(\\\\|[0-7]{1,3}|x.[0-9a-f]?|[\'"abfnrt]|.|$)')
def replace(m):
b = m.group(1)
if len(b) == 0:
raise ValueError("Invalid character escape: '\\'.")
i = b[0]
if i == 120:
v = int(b[1:], 16)
elif 48 <= i <= 55:
v = int(b, 8)
elif i == 34: return b'"'
elif i == 39: return b"'"
elif i == 92: return b'\\'
elif i == 97: return b'\a'
elif i == 98: return b'\b'
elif i == 102: return b'\f'
elif i == 110: return b'\n'
elif i == 114: return b'\r'
elif i == 116: return b'\t'
else:
s = b.decode('ascii')
raise UnicodeDecodeError(
'stringescape', text, m.start(), m.end(), "Invalid escape: %r" % s
)
return bytes((v, ))
result = regex.sub(replace, text)
py2
"\\123omething special".decode('string-escape')
py3
"\\123omething special".encode('utf-8').decode('unicode-escape')
至少在我的情況下,這是等效的:
Py2: my_input.decode('string_escape')
Py3: bytes(my_input.decode('unicode_escape'), 'latin1')
轉換工具.py:
def string_escape(my_bytes):
return bytes(my_bytes.decode('unicode_escape'), 'latin1')
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.