如何在 Python 3 中执行 .decode('string-escape')?[重复]
- 2025-02-21 08:48:00
- admin 原创
- 30
问题描述:
我有一些转义字符串需要取消转义。我想在 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 u p p o r t @ p s i l o c . c o m
并将其变成:
"support@psiloc.com"
完成转换后,我将探测我拥有的字符串是否以 UTF-8 或 UTF-16 编码。
解决方案 1:
您必须使用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'sx00ux00px00px00ox00rx00tx00@x00px00sx00ix00lx00ox00cx00.x00cx00ox00mx00'
>>> _.decode('utf-16-le') # decode from UTF-16-LE
'support@psiloc.com'
解决方案 2:
旧的“字符串转义”编解码器将字节串映射到字节串,并且关于如何处理此类编解码器存在很多争论,因此目前无法通过标准编码/解码接口使用它。
但是,代码仍然存在于 C-API 中(作为PyBytes_En/DecodeEscape
),并且仍然通过未记录的codecs.escape_encode
和向 Python 公开codecs.escape_decode
。
>>> import codecs
>>> codecs.escape_decode(b"ab\ÿ")
(b'abxff', 6)
>>> codecs.escape_encode(b"abxff")
(b'ab\ÿ', 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'sx00ux00px00px00ox00rx00tx00@x00px00sx00ix00lx00ox00cx00.x00cx00ox00mx00'
解决方案 3:
如果您想要对转义序列进行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 u p p o r t @'
r' p s i l o c . c o m ',
'utf-16-le')
'support@psiloc.com'
解决方案 4:
py2
"\\123omething special".decode('string-escape')
py3
"\\123omething special".encode('utf-8').decode('unicode-escape')
解决方案 5:
您不能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''
elif i == 102: return b''
elif i == 110: return b'
'
elif i == 114: return b'
'
elif i == 116: return b' '
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)
解决方案 6:
至少对我来说这是等效的:
Py2: my_input.decode('string_escape')
Py3: bytes(my_input.decode('unicode_escape'), 'latin1')
convertutils.py:
def string_escape(my_bytes):
return bytes(my_bytes.decode('unicode_escape'), 'latin1')