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

12

该二进制字段的描述如下:

使用压缩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代码转换为什么?
4个回答

19

BCD编码使用4位数字,通常仅编码数字0-9。因此,您序列中的每个字节包含2个数字,每个数字包含4位信息。

以下方法使用生成器生成这些数字;我假设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位向右移动,并使用按位与运算选择仅右侧的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。

1

我的项目中的函数。第二个参数表示小数点位数。

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

1
a = b'\x12\x34\x5f'

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

@ack,“hex()”是“bytes”的一种方法(假设在上面的代码中使用了“comp3_to_int(a)”)。请参阅https://docs.python.org/3/library/stdtypes.html#bytes.hex。 - wovano

0
100倍更快的解决方案:
import binascii
binascii.hexlify(byteArray).decode()

另一个较慢的解决方案:
''.join(format(x, '02X') for x in byteArray

如果你需要一个数字,只需将结果包装在int()中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接