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

时间:2013-12-10 04:04:15

标签: 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)

转换后的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)

我注意到在python 3中使用b = b"\x00\x00\x00\x02α\x00\x00\x00\x13привет мир\x00\x00\x00\x02±"将获得异常SyntaxError: bytes can only contain ASCII literal characters., 所以我不得不逃避它们或使用许多+像之前的代码一样。

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

5 个答案:

答案 0 :(得分:2)

另一种解决方案:

b = bytes("привет мир", 'utf-8')

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

答案 1 :(得分:1)

如果您知道字符的编码字节表示,请直接使用它。字节和字节数组根本不包含字符 - 这是字符串/字节区别的全部要点。它们包含可能表示某些特定编码中的字符的字节。我认为该异常文本有点误导 - 字节对象的文字表示只能包含ASCII字符,但这并不意味着对象本身只包含ASCII字符,而不是通过解析表达式{{1包含ASCII字符。

[int("6")]以UTF-8编码为'α',因此您可以将字节构建为b'\xce\xb1'等。

如果您事先不知道相应的字节,使用b=b"\x00\x00\x00\x02\xce\xb1\x00\x00\x00\x13"生成它们是最好的选择。

答案 2 :(得分:1)

这似乎在Python 3.3.2中正常工作:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

b = bytearray("\x00\x00\x00\x02α\x00\x00\x00\x13привет мир"
              "\x00\x00\x00\x02±".encode())

答案 3 :(得分:0)

最后我找到了一个解决方案,这是一个例子:

def to_bytes(string):
    result = b""
    need_eval = ""
    need_encode = ""
    for char in string:
        if char <= "\x7f":
            # if char is ascii, eval it with in b'...'
            if need_encode:
                result += need_encode.encode()
                need_encode = ""
            if char == "'":
                n = 0
                # get how many \ in the end of need_eval 
                for v in reversed(need_eval):
                    if v != "\\":
                        break
                    n += 1
                # if ' is not escaping
                if n % 2 == 0:
                    char = "\\'"
            need_eval += char
        else:
            # if char is non-ascii, encode it to utf-8
            if need_eval:
                result += ast.literal_eval("b'" + need_eval + "'")
                need_eval = ""
            need_encode += char
    result += need_encode.encode()
    result += ast.literal_eval("b'" + need_eval + "'")
    return result

b = to_bytes(r"\x00\x00\x00\x02α\x00\x00\x00\x13привет мир\x00\x00\x00\x02±")

print(repr(b))
print(to_bytes(r"±\xb1"))
print(to_bytes(r"\x90asdfg\\'\''\r\n\xff\u0001"))

指向非ascii部分进行编码并将其他部分转换为eval(因为在python 3上没有string_escape编码,我必须使用ast.literal_eval)。

痛苦是没有效率。

答案 4 :(得分:0)

Python 2函数的工作翻译是:

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

def pack(*s_list):
    # The original passed byte strings encoded in utf-8.
    # I convert the Python 3 Unicode strings to UTF-8 explicitly here.
    s_list = [s.encode('utf8') for s in s_list]
    return b"".join(struct.pack(">I", len(s)) + s for s in s_list)

if __name__ == "__main__":
    print(sys.version)
    a = pack("α", "привет мир", "±")
    # In Python 2 Unicode characters in byte strings were implicitly in the encoding
    # of the file (utf8 above).  Python 3 must be explicit.
    b = "\x00\x00\x00\x02α\x00\x00\x00\x13привет мир\x00\x00\x00\x02±".encode('utf8')
    print(a == b)