how do I .decode('string-escape') in Python3?
我有一些需要转义的转义字符串。 我想用Python做到这一点。
例如,在python2.7中,我可以这样做:
1 2 3 | >>>"\\123omething special".decode('string-escape') 'Something special' >>> |
如何在Python3中做到这一点? 这不起作用:
1 2 3 4 5 | >>> b"\\123omething special".decode('string-escape') Traceback (most recent call last): File"<stdin>", line 1, in <module> LookupError: unknown encoding: string-escape >>> |
我的目标是成为一个像这样的字符串:
1 | s\000u\000p\000p\000o\000r\000t\000@\000p\000s\000i\000l\000o\000c\000.\000c\000o\000m\000 |
并将其转换为:
进行转换后,我将探查我拥有的字符串是否以UTF-8或UTF-16编码。
您必须改为使用
1 | >>> b"\\123omething special".decode('unicode_escape') |
如果从
如果需要字节作为最终结果,则必须再次编码为合适的编码(例如,如果需要保留文字字节值,则为
您的示例实际上是带有转义符的UTF-16数据。从
1 2 3 4 5 | >>> 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 '[email protected]' |
旧的"字符串转义"编解码器将字节字符串映射为字节字符串,并且关于如何使用此类编解码器存在很多争论,因此当前无法通过标准的编码/解码接口使用。
但是,代码仍在C-API中(如
1 2 3 4 5 | >>> import codecs >>> codecs.escape_decode(b"ab\\xff") (b'ab\xff', 6) >>> codecs.escape_encode(b"ab\xff") (b'ab\\xff', 3) |
这些函数返回转换后的
1 2 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' |
您不能在字节字符串上使用
此函数使用正则表达式和自定义替换逻辑实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | 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' ' elif i == 114: return b' ' 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) |
至少在我看来,这是等效的:
1 2 | Py2: my_input.decode('string_escape') Py3: bytes(my_input.decode('unicode_escape'), 'latin1') |
convertutils.py:
1 2 | def string_escape(my_bytes): return bytes(my_bytes.decode('unicode_escape'), 'latin1') |