如何在python 3中声明包含非ascii字符而不转义的字节数组

use*_*220 2 python unicode

这是我在python2中写的一个例子

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import print_function
import sys, struct

def pack(*s_list):
    return b"".join(struct.pack(">I", len(s)) + s for s in s_list)

if __name__ == "__main__":
    print(sys.version)
    a = pack("?", "?????? ???", "±")
    b = b"\x00\x00\x00\x02?\x00\x00\x00\x13?????? ???\x00\x00\x00\x02±"
    print(a == b)
Run Code Online (Sandbox Code Playgroud)

以及python 3的转换代码,

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys, struct

def pack(*s_list):
    return b"".join(struct.pack(">I", len(b)) + b for b in (s.encode() for s in s_list))

if __name__ == "__main__":
    print(sys.version)
    a = pack("?", "?????? ???", "±")
    b = b"\x00\x00\x00\x02?" + "?".encode() + b"\x00\x00\x00\x13" + "?????? ???".encode() + b"\x00\x00\x00\x02" + "±".encode()
    print(a == b)
Run Code Online (Sandbox Code Playgroud)

我注意到b = b"\x00\x00\x00\x02?\x00\x00\x00\x13?????? ???\x00\x00\x00\x02±"在 python 3 中使用会得到一个异常SyntaxError: bytes can only contain ASCII literal characters.,所以我不得不像以前的代码一样将它们全部转义或使用 many + 。

有没有更好的方法在python3中声明包含非ascii字符的字节数组?

小智 7

另一种解决方案:

b = bytes("?????? ???", 'utf-8')
Run Code Online (Sandbox Code Playgroud)

似乎这是更好的解决方案,因为它具有较少的复制操作。


use*_*220 1

最后我找到了一个解决方案来做到这一点,这是示例:

\n\n
def to_bytes(string):\n    result = b""\n    need_eval = ""\n    need_encode = ""\n    for char in string:\n        if char <= "\\x7f":\n            # if char is ascii, eval it with in b\'...\'\n            if need_encode:\n                result += need_encode.encode()\n                need_encode = ""\n            if char == "\'":\n                n = 0\n                # get how many \\ in the end of need_eval \n                for v in reversed(need_eval):\n                    if v != "\\\\":\n                        break\n                    n += 1\n                # if \' is not escaping\n                if n % 2 == 0:\n                    char = "\\\\\'"\n            need_eval += char\n        else:\n            # if char is non-ascii, encode it to utf-8\n            if need_eval:\n                result += ast.literal_eval("b\'" + need_eval + "\'")\n                need_eval = ""\n            need_encode += char\n    result += need_encode.encode()\n    result += ast.literal_eval("b\'" + need_eval + "\'")\n    return result\n\nb = to_bytes(r"\\x00\\x00\\x00\\x02\xce\xb1\\x00\\x00\\x00\\x13\xd0\xbf\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82 \xd0\xbc\xd0\xb8\xd1\x80\\x00\\x00\\x00\\x02\xc2\xb1")\n\nprint(repr(b))\nprint(to_bytes(r"\xc2\xb1\\xb1"))\nprint(to_bytes(r"\\x90asdfg\\\\\'\\\'\'\\r\\n\\xff\\u0001"))\n
Run Code Online (Sandbox Code Playgroud)\n\n

重点是采用非ascii部分进行编码,并将其他部分进行eval(因为python 3上没有string_escape编码,我不得不使用ast.literal_eval)。

\n\n

痛苦的是它效率不高。

\n