精心制作的十六进制字符串在字符串格式中正确,一旦传递给 unhexlify() 就会出现格式错误
Crafted hex string correct in string format, malforms once passed to unhexlify()
def craft_integration(xintegration_time):
integration_time = xintegration_time
integration_time_str = str(integration_time)
integration_time_str = integration_time_str.encode('utf-8')
integration_time_hex = integration_time_str.hex()
return integration_time_hex
def send_set_integration(xtime):
int_time_hex = decoder_crafter.craft_integration(xtime)
set_hex = "c1c000000000000010001100000000000000000000000004"+int_time_hex+"1400000000000000000000000000000000000000c5c4c3c2"
set_hex = str(set_hex)
print(set_hex)
set_hex = unhexlify(set_hex)
例如,输入'1000'。
用 craft_integration() 变成 31303030。
然后将其插入到默认的十六进制字符串中。
输出为:
c1c00000000000001000110000000000000000000000000431303030140000000000000000000000000000000000000c5c4c3c2
当使用 unhexlify() 时,输出为:
b'\xc1\xc0\x00\x00\x00\x00\x00\x00\x10\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x041000\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc5\xc4\xc3\xc2'
\x041000 是 \x04 和 1000 的结合,它是 原始 输入值,而不是转换后的值。
为什么会这样?
事实上,您所拥有的只是您想要的值被 bytes.__repr__
的默认实现渲染到一个表单中,您没有预料到它对您想要的东西没有帮助。
从更基本的层面开始:在 Python 中,bytes
类型中的任何元素(好吧,任何 "byte",即一组 8 位)通常是以二进制形式存储在机器某处的原始数字表示形式。为了 "print" 将它们输出到控制台供人类使用,必须将其转换为控制台可以解释的形式,以便可以使用正确的字形来表示基础值。对于许多值,例如 0
(或二进制的 00000000
),Python 将使用 \x00
来表示。 \
是开始转义序列的转义字符,后面的 x
表示转义序列后跟 2 个十六进制字符,将这两个字符与整个序列组合将形成使用四个字符表示该单个字节。同样对于 255
,在二进制中将是 11111111
,作为 bytes
类型的一部分的相同值将被编码为 \xff
.
现在有例外 - 如果给定值落在 ASCII range, and that it in the range of printable characters 内,表示将改为相应的 ASCII 字符。因此,在十六进制 30
(十进制 48
)的情况下,将其呈现为 bytes
类型的一部分将显示 0
而不是 \x30
,如0
是对应的可打印字符。
因此,对于您的情况,以 b'\x041000'
形式在控制台中打印出的 bytes
表示实际上并不是一个很大的 \x
值,因为 \x
转义序列仅适用于恰好两个后续字符 - 所有后续字符(即 1000
)实际上都使用可打印字符表示,否则将表示为 \x31\x30\x30\x30
.
对于那些不介意使用字节的十进制表示形式的人,还有另一种方法可用 - 只需将 bytes
转换为 bytearray
,然后转换为 list
。我们以两个nul字节(b'\x00\x00'
)为例:
>>> list(bytearray(b'\x00\x00'))
[0, 0]
很明显,这两个 nul 字节将对应两个零值。现在尝试使用令人困惑的 b'\x04\x31\x30\x30\x30'
渲染成 b'\x041000'
:
>>> list(bytearray(b'\x041000'))
[4, 49, 48, 48, 48]
我们可以注意到,它实际上是 5 个字节,在 5 个元素的列表中用相应的十进制数字呈现。
通常很容易混淆实际值与计算机控制台上显示和可视化的值。不幸的是,我们使用的工具有时会加剧这种混乱,但作为程序员,我们应该理解这一点,并设法为我们工作的用户尽量减少这种混乱,因为这个例子表明,并不是每个人都有直觉 bytes
的某些表示可能而是表示为可打印的 ASCII。
def craft_integration(xintegration_time):
integration_time = xintegration_time
integration_time_str = str(integration_time)
integration_time_str = integration_time_str.encode('utf-8')
integration_time_hex = integration_time_str.hex()
return integration_time_hex
def send_set_integration(xtime):
int_time_hex = decoder_crafter.craft_integration(xtime)
set_hex = "c1c000000000000010001100000000000000000000000004"+int_time_hex+"1400000000000000000000000000000000000000c5c4c3c2"
set_hex = str(set_hex)
print(set_hex)
set_hex = unhexlify(set_hex)
例如,输入'1000'。 用 craft_integration() 变成 31303030。 然后将其插入到默认的十六进制字符串中。
输出为:
c1c00000000000001000110000000000000000000000000431303030140000000000000000000000000000000000000c5c4c3c2
当使用 unhexlify() 时,输出为:
b'\xc1\xc0\x00\x00\x00\x00\x00\x00\x10\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x041000\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc5\xc4\xc3\xc2'
\x041000 是 \x04 和 1000 的结合,它是 原始 输入值,而不是转换后的值。
为什么会这样?
事实上,您所拥有的只是您想要的值被 bytes.__repr__
的默认实现渲染到一个表单中,您没有预料到它对您想要的东西没有帮助。
从更基本的层面开始:在 Python 中,bytes
类型中的任何元素(好吧,任何 "byte",即一组 8 位)通常是以二进制形式存储在机器某处的原始数字表示形式。为了 "print" 将它们输出到控制台供人类使用,必须将其转换为控制台可以解释的形式,以便可以使用正确的字形来表示基础值。对于许多值,例如 0
(或二进制的 00000000
),Python 将使用 \x00
来表示。 \
是开始转义序列的转义字符,后面的 x
表示转义序列后跟 2 个十六进制字符,将这两个字符与整个序列组合将形成使用四个字符表示该单个字节。同样对于 255
,在二进制中将是 11111111
,作为 bytes
类型的一部分的相同值将被编码为 \xff
.
现在有例外 - 如果给定值落在 ASCII range, and that it in the range of printable characters 内,表示将改为相应的 ASCII 字符。因此,在十六进制 30
(十进制 48
)的情况下,将其呈现为 bytes
类型的一部分将显示 0
而不是 \x30
,如0
是对应的可打印字符。
因此,对于您的情况,以 b'\x041000'
形式在控制台中打印出的 bytes
表示实际上并不是一个很大的 \x
值,因为 \x
转义序列仅适用于恰好两个后续字符 - 所有后续字符(即 1000
)实际上都使用可打印字符表示,否则将表示为 \x31\x30\x30\x30
.
对于那些不介意使用字节的十进制表示形式的人,还有另一种方法可用 - 只需将 bytes
转换为 bytearray
,然后转换为 list
。我们以两个nul字节(b'\x00\x00'
)为例:
>>> list(bytearray(b'\x00\x00'))
[0, 0]
很明显,这两个 nul 字节将对应两个零值。现在尝试使用令人困惑的 b'\x04\x31\x30\x30\x30'
渲染成 b'\x041000'
:
>>> list(bytearray(b'\x041000'))
[4, 49, 48, 48, 48]
我们可以注意到,它实际上是 5 个字节,在 5 个元素的列表中用相应的十进制数字呈现。
通常很容易混淆实际值与计算机控制台上显示和可视化的值。不幸的是,我们使用的工具有时会加剧这种混乱,但作为程序员,我们应该理解这一点,并设法为我们工作的用户尽量减少这种混乱,因为这个例子表明,并不是每个人都有直觉 bytes
的某些表示可能而是表示为可打印的 ASCII。