Python,如何解码二进制编码的十进制(BCD)



二进制字段的描述为:

主叫号码,用压缩BCD码表示,剩余位用"0xF"填充

我尝试过用结构格式'16c'打印,我得到:('3', 'x00', 'x02', 'x05', 'x15', 'x13', 'G', 'O', 'xff', 'xff', 'xff', 'xff', 'xff', 'xff', 'xff', 'xff'),如果我使用'16b',我得到(51, 0, 2, 5, 21, 19, 71, 79, -1, -1, -1, -1, -1, -1, -1, -1)。这是不对的,我应该得到电话号码,上面的号码是无效的。

print struct.unpack_from('>16b', str(data.read()),offset=46)

上面的代码不起作用,我得到了无效的数字。我应该用什么格式来解压缩这个16字节的字段,以及如何转换BCD码?

BCD码每个数字4位,通常只编码数字0-9。因此,序列中的每个字节包含2个数字,每4位信息中就有1个。

以下方法使用生成器来生成这些数字;我假设0xF值意味着后面没有更多的数字:

def bcdDigits(chars):
    for char in chars:
        char = ord(char)
        for val in (char >> 4, char & 0xF):
            if val == 0xF:
                return
            yield val

在这里,我使用右移运算符将最左边的4位向右移动,并使用逐位and来选择最右边的4位。

演示:

>>> characters = ('3', 'x00', 'x02', 'x05', 'x15', 'x13', 'G', 'O', 'xff', 'xff', 'xff', 'xff', 'xff', 'xff', 'xff', 'xff')
>>> list(bcdDigits(characters))
[3, 3, 0, 0, 0, 2, 0, 5, 1, 5, 1, 3, 4, 7, 4]

该方法适用于c输出;如果直接传递整数,则可以跳过方法中的ord调用(但使用B无符号变量)。或者,您可以直接从文件中读取这16个字节,并在不使用struct的情况下将此函数直接应用于这些字节。

a = b'x12x34x5f'
def comp3_to_int(a):
    b = a.hex()
    c = int(b[0:len(b)-1])
    if b[len(b)-1:] == 'd':
        c = -c
    return c

我的项目中的函数。第二个参数放置小数点。

def bcd_decode(data: bytes, decimals: int):
    '''
    Decode BCD number
    '''
    res = 0
    for n, b in enumerate(reversed(data)):
        res += (b & 0x0F) * 10 ** (n * 2 - decimals)
        res += (b >> 4) * 10 ** (n * 2 + 1 - decimals)
    return res