Python 3 - 解码包含 hex 和 unicode 混合的字节
Python 3 - Decoding bytes that contains a mix of hex and unicode
我正在将 a codebase for the Lasersaur laser cutter 从 Python2 移植到 Python3,我在解码来自板载 Arduino 的串行数据时遇到了一些麻烦。数据以字节流的形式出现,混合了十六进制和 unicode 数据,如下所示:
bytes: b'AC\xfb\xff\xff\xbfx\x85\x80\x80\xc0y\x80\x80\x80\xc0z'
data: A C 251 255 255 x 133 128 128 y 128 128 128 z
Python2能够对混合类型的数据进行steamroll,将串口数据读入为一串字符,之后ord()
判断该字符代表的是数据还是状态字符。您可以在 line 367 here.
开始的原始 Python2 代码中看到这是如何实现的
ord(data): 65 67 251 255 255 120 133 128 128 121 128 128 128 122
Python3 对编码更严格,当我尝试 bytes.decode('utf-8')
时抛出以下错误,因为它到达第一个十六进制数据 b'x\fb'
并因为它是不同的而阻塞格式。混用几种不同的编解码器并不能带来更好的结果。
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xfb in position 2: invalid start byte
我发现 this Whosebug thread 几乎完全满足了我的需要,但似乎 Python 3 中的错误处理不再有效,并且在我尝试那里的解决方案:TypeError: 'UnicodeDecodeError' object is not subscriptable
.
我可以修改 Arduino 上的板载代码以获得更合理的串行编码,但我移植到 Python3 的主要原因是我无法获得正确的代码(阅读:旧的) Python2 库来执行代码,我不想 运行 进入我无意中进入无法与板载 arduino 通信的状态的场景。
我想做的是尽可能地模仿原始功能,并得到我可以调用 ord()
的一串字符,或者一个字符和数字的混合列表。我有点不知道该怎么做。
您没有 'mixed' 数据,您有一个字节对象。打印的时候,Python将所有值对应ASCII中一个字母的字节表示为一个字母,以帮助我们识别其中的文字。
您可以通过索引访问任何单个字节作为整数:
data = b'AC\xfb\xff\xff\xbfx\x85\x80\x80\xc0y\x80\x80\x80\xc0z'
print(data[0])
# 65
该值以整数形式返回。 (此处为 65,对应于 ASCII 中的 'A',因此它在字节字符串中的表示形式。)
因此,将字节转换为整数列表的简单方法是:
data_as_int = [b for b in data]
或更简单:
data_as_int = list(data)
这给了我们:
print(data_as_int)
# [65, 67, 251, 255, 255, 191, 120, 133, 128, 128, 192, 121, 128, 128, 128, 192, 122]
关于您将字节转换为字符串的想法,以便之后使用 ord
:您可以这样做,但是您必须使用像 latin1
这样的编码,其中每个字节对应到一个字符 - utf8
不是这种情况。
所以,你可以这样做:
data_as_int = [ord(c) for c in data.decode('latin1')]
但这不如上面的解决方案直接。
我正在将 a codebase for the Lasersaur laser cutter 从 Python2 移植到 Python3,我在解码来自板载 Arduino 的串行数据时遇到了一些麻烦。数据以字节流的形式出现,混合了十六进制和 unicode 数据,如下所示:
bytes: b'AC\xfb\xff\xff\xbfx\x85\x80\x80\xc0y\x80\x80\x80\xc0z'
data: A C 251 255 255 x 133 128 128 y 128 128 128 z
Python2能够对混合类型的数据进行steamroll,将串口数据读入为一串字符,之后ord()
判断该字符代表的是数据还是状态字符。您可以在 line 367 here.
ord(data): 65 67 251 255 255 120 133 128 128 121 128 128 128 122
Python3 对编码更严格,当我尝试 bytes.decode('utf-8')
时抛出以下错误,因为它到达第一个十六进制数据 b'x\fb'
并因为它是不同的而阻塞格式。混用几种不同的编解码器并不能带来更好的结果。
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xfb in position 2: invalid start byte
我发现 this Whosebug thread 几乎完全满足了我的需要,但似乎 Python 3 中的错误处理不再有效,并且在我尝试那里的解决方案:TypeError: 'UnicodeDecodeError' object is not subscriptable
.
我可以修改 Arduino 上的板载代码以获得更合理的串行编码,但我移植到 Python3 的主要原因是我无法获得正确的代码(阅读:旧的) Python2 库来执行代码,我不想 运行 进入我无意中进入无法与板载 arduino 通信的状态的场景。
我想做的是尽可能地模仿原始功能,并得到我可以调用 ord()
的一串字符,或者一个字符和数字的混合列表。我有点不知道该怎么做。
您没有 'mixed' 数据,您有一个字节对象。打印的时候,Python将所有值对应ASCII中一个字母的字节表示为一个字母,以帮助我们识别其中的文字。
您可以通过索引访问任何单个字节作为整数:
data = b'AC\xfb\xff\xff\xbfx\x85\x80\x80\xc0y\x80\x80\x80\xc0z'
print(data[0])
# 65
该值以整数形式返回。 (此处为 65,对应于 ASCII 中的 'A',因此它在字节字符串中的表示形式。)
因此,将字节转换为整数列表的简单方法是:
data_as_int = [b for b in data]
或更简单:
data_as_int = list(data)
这给了我们:
print(data_as_int)
# [65, 67, 251, 255, 255, 191, 120, 133, 128, 128, 192, 121, 128, 128, 128, 192, 122]
关于您将字节转换为字符串的想法,以便之后使用 ord
:您可以这样做,但是您必须使用像 latin1
这样的编码,其中每个字节对应到一个字符 - utf8
不是这种情况。
所以,你可以这样做:
data_as_int = [ord(c) for c in data.decode('latin1')]
但这不如上面的解决方案直接。