在Python 3中如何使用.decode('string-escape')?
我有一些被转义的字符串,需要把它们还原成正常的字符串。我想用Python来实现这个。
比如,在Python 2.7中,我可以这样做:
>>> "\\123omething special".decode('string-escape')
'Something special'
>>>
那么在Python 3中,我该怎么做呢?这个方法不行:
>>> b"\\123omething special".decode('string-escape')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
LookupError: unknown encoding: string-escape
>>>
我的目标是能够把像这样的字符串:
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编码的。
6 个回答
36
以前有一种叫“字符串转义”的编码方式,它可以把字节串转换成字节串。关于这种编码方式,大家讨论了很多,所以现在在标准的编码和解码接口中是无法使用的。
不过,这个功能的代码还是在C语言的API里(叫做 PyBytes_En/DecodeEscape
),并且通过一些没有文档说明的方式,仍然可以在Python中使用,分别是 codecs.escape_encode
和 codecs.escape_decode
。
>>> 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'
74
你需要使用 unicode_escape
来处理:
>>> b"\\123omething special".decode('unicode_escape')
如果你一开始用的是 str
对象(相当于 Python 2.7 的 unicode),你需要先把它转换成字节,然后再用 unicode_escape
解码。
如果你最终需要的是字节数据,你还得再编码成合适的格式(比如用 .encode('latin1')
,如果你想保留字节的原始值;前256个Unicode编码点是逐一对应的)。
你的例子实际上是带有转义的UTF-16数据。先用 unicode_escape
解码,再转回 latin1
以保留字节,然后再从 utf-16-le
(没有字节顺序标记的UTF 16小端格式)解码:
>>> 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'
27
如果你想要把字符串中的转义序列进行解码,也就是说输入和输出都是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'