如何在Python3中解码(';字符串转义';)?

如何在Python3中解码(';字符串转义';)?,python,python-3.x,escaping,Python,Python 3.x,Escaping,我有一些转义字符串需要取消转义。我想用Python来做这件事 例如,在python2.7中,我可以这样做: >>> "\\123omething special".decode('string-escape') 'Something special' >>> 如何在Python3中实现它?这不起作用: >>> b"\\123omething special".decode('string-escape') Traceback (most

我有一些转义字符串需要取消转义。我想用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
>>> 
并将其转化为:

"support@psiloc.com"

完成转换后,我将探测我拥有的字符串是否以UTF-8或UTF-16编码。

您必须使用
unicode\u escape

>>> b"\\123omething special".decode('unicode_escape')
如果改为从
str
对象开始(相当于python 2.7 unicode),则需要先编码到字节,然后使用
unicode\u escape
进行解码

如果需要字节作为最终结果,则必须再次编码为合适的编码(
.encode('latin1')
,例如,如果需要保留文字字节值,则必须将前256个Unicode代码点映射为1对1)

您的示例实际上是带有转义符的UTF-16数据。从
unicode\u escape
解码,返回到
latin1
以保留字节,然后从
utf-16-le
(utf 16小端无BOM):


您不能在字节字符串上使用
unicode\u escape
(或者更确切地说,您可以,但它并不总是返回与Python 2上的
string\u escape
相同的内容)–小心

此函数使用正则表达式和自定义替换逻辑实现
string\u 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)
def unescape(文本):
regex=re.compile(b'\\\\\\\\\[0-7]{1,3}x.[0-9a-f]?[\''abfnrt].$))
def更换(m):
b=m组(1)
如果len(b)==0:
raise VALUERROR(“无效字符转义:'\\'.”)
i=b[0]
如果i==120:
v=int(b[1:],16)
elif 48旧的“字符串转义”编解码器将ByTestRing映射到ByTestRing,关于如何使用此类编解码器,存在很多争论,因此目前无法通过标准编码/解码接口使用

但是,代码仍然存在于C-API中(如
PyBytes\u En/decodeScape
),并且仍然通过未记录的
codecs.escape\u encode
codecs.escape\u decode
向Python公开

>>> import codecs
>>> codecs.escape_decode(b"ab\\xff")
(b'ab\xff', 6)
>>> codecs.escape_encode(b"ab\xff")
(b'ab\\xff', 3)
这些函数返回转换后的
字节
对象,加上一个数字,指示处理了多少字节……您可以忽略后者

>>> 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'

至少在我的情况下,这相当于:

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')

如果要对转义序列进行str-to-str解码,则输入和输出均为Unicode:

def string_转义(s,encoding='utf-8'):
将(s.encode('latin1')#返回到字节,这是“unicode转义”所要求的
.decode(“unicode-escape”)#执行实际的八进制转义解码
.encode('latin1')#1:1映射回字节
.解码(编码)#解码原始编码
测试:

>>字符串\u转义('\\123omething special')
“一些特别的东西”
>>>字符串\u转义(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'
py2

py3


这会将我的二进制对象变成Unicode对象。我想让它成为一个二进制对象。有什么办法吗?@vy32:解码后对它进行编码?你希望它适合什么编码?ASCII,拉丁语1?它可以是任何东西。该程序探测各种可能的编码。它可能是ASCII、UTF-8、UTF-16、拉丁语1或其他十几种可能的编码。@vy32:然后通过解码从
unicode\u escape
转换为“正确”字节,然后通过
latin1
返回到字节(这与1对1映射非常吻合)。然后你就有字节来尝试解码。你绝对确定这些是转义而不是文字字节吗?它们是文字字节!有一个反斜杠,然后是一个0,然后是另一个0,然后是第三个0…我有一个程序,它读取二进制文件并输出这样的信息。它输出文件中实际存在的二进制文件。有时文件的t是UTF-8编码的,它只是通过。但是,如果它不是有效的UTF-8,它将以这种方式进行编码。最低投票的答案是Py3。请注意,如果您同意总是以UTF-8结尾,您可以这样做:
s.encode('latin1','backslashreplace')。decode('unicode-escape'))
——参见@GlenWhitney,这似乎与python 2中的
decode('string-escape')
做的事情并不完全相同,即使对于UTF-8也是如此。例如,从
s='\\xe7\\xa7\\x98'
开始,python2
打印s.decode('string-escape')
打印
ç§
。py2是否将
r
放在字符串前面,这样就不需要转义“`”?
Py2: my_input.decode('string_escape')
Py3: bytes(my_input.decode('unicode_escape'), 'latin1')
def string_escape(my_bytes):
    return bytes(my_bytes.decode('unicode_escape'), 'latin1')
"\\123omething special".decode('string-escape')
"\\123omething special".encode('utf-8').decode('unicode-escape')