英文:
Python struct reverse unpack
问题
尝试以以下方式解包结构以获得 '0123456789':
b"\x10\x32\x54\x76\x98"
也许还有其他方法,而不是编写自己的函数来实现这个目标?
谢谢。
英文:
I'm trying to unpack structure as shown below in this way to get '0123456789'
b"\x10\x32\x54\x76\x98"
Maybe there is other way then writing own function to do so ?
Thanks
答案1
得分: 3
I think it's easier to debug if you use your own function. However, if you want a one-line command to turn this into a string you can do like so:
X = b"\x10\x32\x54\x76\x98";
tmp = "".join([hex(i)[:1:-1].zfill(2) for i in X])
print(tmp)
>>> 0123456789
Basically it turns each byte to hexadecimal (which handles splitting methods), so we split them to read them backward without "0x".
Finally, we join them using an empty string separator.
EDIT
As pointed by Alain T. I updated the code and added the zfill()
method to force the string length of each byte to 2 to avoid missing integers like in the example:
b"\x10\x32\x05\x76\x98"
.
英文:
I think it's easier to debug if you use your own function. However, if you want a one line command to turn this into a string you can do like so:
X = b"\x10\x32\x54\x76\x98"
tmp = "".join([hex(i)[:1:-1].zfill(2) for i in X])
print(tmp)
>>> 0123456789
Basically it turns each byte to hexadecimal (which handles splitting methods), so we split them to read them backward without "0x"
.
Finally we join them using an empty string separator.
EDIT
As pointed by Alain T. I updated the code and added the zfill()
method to force the string length of each byte to 2 to avoid missing integers like in the example:
b"\x10\x32\x05\x76\x98"
.
答案2
得分: 0
以下是翻译好的代码部分:
使用reduce函数可以在数学上获取一个整数:
from functools import reduce
X = b"\x10\x32\x45\x76\x98"
d = reduce(lambda r,b:r*100+b%16*10+b//16,X,0)
print(d)
# 123546789
或者,不使用库,使用sum()和推导式:
d = sum( (d%16*10+d//16)*100**i for i,d in enumerate(X[::-1]))
print(d)
# 123546789
如果需要它是一个带有前导零的字符串,可以使用format方法:
d = ("{:02x}"*len(X)).format(*X[::-1])[::-1]
print(d)
0123546789
或者使用join函数和推导式:
d = "".join(f"{d%16}{d//16}" for b in X)
print(d)
0123546789
对于字符串输出,不带前导零,可以在将它们转换为整数之前交换每个字节的nibbles,然后使用该整数的十六进制表示(这是最快的字符串转换):
d = hex(int.from_bytes((b%16*16+b//16 for b in X),"big"))[2:]
print(d)
123546789
性能比较:
tests = {
"reduce ": lambda : reduce(lambda r,b:r*100+b%16*10+b//16,X,0),
"from_bytes": lambda : hex(int.from_bytes((b%16*16+b//16 for b in X),"big"))[2:],
"format ": lambda : ("{:02x}"*len(X)).format(*X[::-1])[::-1],
"join ": lambda : "".join(f"{d%16}{d//16}" for d in X),
"sum ": lambda : sum( (d%16*10+d//16)*100**i for i,d in enumerate(X[::-1])),
}
from timeit import timeit
for name,fn in tests.items():
print(name,fn(),timeit(fn,number=1000000))
reduce 123546789 1.1987413900000001
from_bytes 123546789 1.245261141
format 0123546789 1.517380332
join 0123546789 1.8026392529999997
sum 123546789 2.1293131119999993
请注意,这是代码的翻译版本,不包括问题中的其他内容。
英文:
You could get an integer mathematically using reduce:
from functools import reduce
X = b"\x10\x32\x45\x76\x98"
d = reduce(lambda r,b:r*100+b%16*10+b//16,X,0)
print(d)
# 123546789
Or, without libraries using sum() and a comprehension:
d = sum( (d%16*10+d//16)*100**i for i,d in enumerate(X[::-1]))
print(d)
# 123546789
If you need it to be a string, with leading zero, you can use the format method
d = ("{:02x}"*len(X)).format(*X[::-1])[::-1]
print(d)
0123546789
or the join function and a comprehension:
d = "".join(f"{d%16}{d//16}" for b in X)
print(d)
0123546789
For a string output, without leading zeros, you can swap the nibles of each byte before converting them to an integer and then use the hex representation of that integer (this is the fastest string conversion):
d = hex(int.from_bytes((b%16*16+b//16 for b in X),"big"))[2:]
print(d)
123546789
Performance comparisons:
tests = {
"reduce ": lambda : reduce(lambda r,b:r*100+b%16*10+b//16,X,0),
"from_bytes": lambda : hex(int.from_bytes((b%16*16+b//16 for b in X),"big"))[2:],
"format ": lambda : ("{:02x}"*len(X)).format(*X[::-1])[::-1],
"join ": lambda : "".join(f"{d%16}{d//16}" for d in X),
"sum ": lambda : sum( (d%16*10+d//16)*100**i for i,d in enumerate(X[::-1])),
}
from timeit import timeit
for name,fn in tests.items():
print(name,fn(),timeit(fn,number=1000000))
reduce 123546789 1.1987413900000001
from_bytes 123546789 1.245261141
format 0123546789 1.517380332
join 0123546789 1.8026392529999997
sum 123546789 2.1293131119999993
答案3
得分: 0
这里还有另一种只使用 f-strings 和一点算术运算来完成的方法:
X = b"\x10\x32\x54\x76\x98"
for b in X:
print(f'{b%16}{b//16}', end='')
输出:
0123456789
注意:
如果你需要一个单独的字符串,那么在循环内构建它,而不是打印。
英文:
Here's yet another way to do this just using f-strings and a little bit of arithmetic:
X = b"\x10\x32\x54\x76\x98"
for b in X:
print(f'{b%16}{b//16}', end='')
Output:
0123456789
Note:
If you need a single string then just build it within the loop instead of printing
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论