使用Python Numpy解析包含BCD(二进制编码十进制)值的二进制文件
我有一个二进制文件,其中一些字段编码为BCD(二进制编码的十进制)。示例如下 14 75 26 58 87 7F(十六进制格式的原始字节) 我使用(np.void,6)从二进制文件读取和转换,下面是我得到的输出 b'\x14\x75\x26\x58\x87\x7F' 但是我希望得到的输出是'14752658877',没有使用numpy填充字符'F' 代码如下: 打开(文件名为“rb”)作为f:使用Python Numpy解析包含BCD(二进制编码十进制)值的二进制文件,python,numpy,Python,Numpy,我有一个二进制文件,其中一些字段编码为BCD(二进制编码的十进制)。示例如下 14 75 26 58 87 7F(十六进制格式的原始字节) 我使用(np.void,6)从二进制文件读取和转换,下面是我得到的输出 b'\x14\x75\x26\x58\x87\x7F' 但是我希望得到的输出是'14752658877',没有使用numpy填充字符'F' 代码如下: 打开(文件名为“rb”)作为f: 此外,输入文件包含许多固定长度的二进制记录。使用numpy将其转换并存储为ascii文件的有效方法是什
此外,输入文件包含许多固定长度的二进制记录。使用numpy将其转换并存储为ascii文件的有效方法是什么 我不知道numpy是否能以某种方式加速这一过程,但可以快速构造一个特定的函数:
fastDict = {16*(i//10)+(i%10):i for i in range(100)}
def bcdToInteger(bcd):
result = 0
while bcd and bcd[0] in fastDict:
result *= 100
result += fastDict[bcd[0]]
bcd = bcd[1:]
if bcd and bcd[0] & 0xf0 <= 0x90:
result *= 10
result += bcd[0]>>4
if bcd[0] & 0xf <= 9:
result *= 10
result += bcd[0] & 0x0f
return result
>>> print (bcdToInteger(b'\x14\x75\x26\x58\x87\x7F')) # your sequence
14752658877
>>> print (bcdToInteger(b'\x12\x34\xA0')) # first invalid nibble ends
1234
>>> print (bcdToInteger(b'\x00\x00\x99')) # and so does an end of string
99
>>> print (bcdToInteger(b'\x1F')) # a single nibble value
1
fastDict={16*(i//10)+(i%10):i代表范围(100)内的i)
def bcd指示灯(bcd):
结果=0
而fastDict中的bcd和bcd[0]为:
结果*=100
结果+=fastDict[bcd[0]]
bcd=bcd[1:]
如果bcd和bcd[0]&0xf0>4
如果bcd[0]&0xf>>打印(bcdToInteger(b'\x14\x75\x26\x58\x87\x7F'))#您的顺序
14752658877
>>>打印(bcdToInteger(b'\x12\x34\xA0'))#第一个无效的半字节结束
1234
>>>打印(bcdToInteger(b'\x00\x00\x99'))#以及字符串的结尾
99
>>>打印(bcdToInteger(b'\x1F'))#单个半字节值
1.
只要您继续向它输入有效的BCD字节,它就会将结果乘以100并添加两个新数字。只有最后一个字节需要进一步检查:如果最高的半字节是有效的,那么到目前为止的结果将乘以10,该半字节将被相加。如果最低半字节也有效,则重复此操作
fastDict
是为了加快速度。它是一个字典,返回从00
到99
的所有100个十六进制字节的正确值,因此实际计算的数量尽可能少。您可以不使用字典,但这意味着您必须在if
块中对每个字节进行比较和计算。显示示例代码。下面是代码:open(filename,“rb”)为f:True:chunk=f.read(chunksize)if(chunk):dt=np.dtype([('a','b'),('b','>i4'),('c','S15'),('d',np.str,7),('e','S7'),('f',np.void,6)]x=np.frombuffer(chunk,dtype=dt)print(x)其他:请编辑原始问题,添加上述代码,保留所有格式和缩进。你好,李嘉图,我已编辑原始问题以添加代码。F不是填充字符。这是十六进制值的一部分。感谢您的解决方案。我正在使用binascii.hexlify(bcdvalue).decode('utf-8').rstrip('f')来获得首选结果。但我正在寻找高效的解决方案,因为我有很多这样的专栏。我们每天的记录量接近10亿条。@RajKB:我觉得我的解决方案相当有效。正如您在中所看到的,它们使用昂贵的位移位,并且每个字节比较两次;我的代码避免了这一点。然而,使用C语言中的自定义扩展可以编写更快的代码,但我不打算尝试。嗨,我正在尝试您的解决方案。但是我在运行代码时遇到了以下错误。你能检查一下吗。文件“”,第7行,在bcdToInteger中,如果bcd和bcd[0]&0xf0,请忽略上面的注释。是的,它忽略了。非常感谢你的回答。
fastDict = {16*(i//10)+(i%10):i for i in range(100)}
def bcdToInteger(bcd):
result = 0
while bcd and bcd[0] in fastDict:
result *= 100
result += fastDict[bcd[0]]
bcd = bcd[1:]
if bcd and bcd[0] & 0xf0 <= 0x90:
result *= 10
result += bcd[0]>>4
if bcd[0] & 0xf <= 9:
result *= 10
result += bcd[0] & 0x0f
return result
>>> print (bcdToInteger(b'\x14\x75\x26\x58\x87\x7F')) # your sequence
14752658877
>>> print (bcdToInteger(b'\x12\x34\xA0')) # first invalid nibble ends
1234
>>> print (bcdToInteger(b'\x00\x00\x99')) # and so does an end of string
99
>>> print (bcdToInteger(b'\x1F')) # a single nibble value
1