Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/html/80.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何将整数转换为可变长度字节字符串?_Python_Integer_Bit Manipulation_Endianness_Byte - Fatal编程技术网

Python 如何将整数转换为可变长度字节字符串?

Python 如何将整数转换为可变长度字节字符串?,python,integer,bit-manipulation,endianness,byte,Python,Integer,Bit Manipulation,Endianness,Byte,我想将整数(int或long)转换为大端字节字符串。字节字符串必须具有可变长度,以便只使用最小数量的字节(已知前面数据的总长度,因此可以推断可变长度) 我目前的解决办法是 import bitstring bitstring.BitString(hex=hex(456)).tobytes() 这显然取决于机器的尾数,并给出错误的结果,因为0位是附加的,没有前缀 有没有人知道这样做的方法,而不必对int的长度或长度做任何假设?类似的东西。未测试(直到下一次编辑)。对于Python2.x。假设n

我想将整数(
int
long
)转换为大端字节字符串。字节字符串必须具有可变长度,以便只使用最小数量的字节(已知前面数据的总长度,因此可以推断可变长度)

我目前的解决办法是

import bitstring

bitstring.BitString(hex=hex(456)).tobytes()
这显然取决于机器的尾数,并给出错误的结果,因为0位是附加的,没有前缀


有没有人知道这样做的方法,而不必对
int
的长度或长度做任何假设?

类似的东西。未测试(直到下一次编辑)。对于Python2.x。假设n>0

tmp = []
while n:
    n, d = divmod(n, 256)
    tmp.append(chr(d))
result = ''.join(tmp[::-1])
编辑:已测试

如果您不阅读手册,但喜欢Bitbash,请尝试以下方法,而不是
divmod
caper:

d = n & 0xFF; n >>= 8
编辑2:如果您的数字相对较小,则以下速度可能更快:

result = ''
while n:
    result = chr(n & 0xFF) + result
    n >>= 8
编辑3:第二个方法不假设int已经是bigendian。以下是在声名狼藉的小印度环境中发生的事情:

Python 2.7 (r27:82525, Jul  4 2010, 09:01:59) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> n = 65539
>>> result = ''
>>> while n:
...     result = chr(n & 0xFF) + result
...     n >>= 8
...
>>> result
'\x01\x00\x03'
>>> import sys; sys.byteorder
'little'
>>>

使用
struct
itertools
的解决方案:

>>> import itertools, struct
>>> "".join(itertools.dropwhile(lambda c: not(ord(c)), struct.pack(">i", 456))) or chr(0)
'\x01\xc8'
我们可以使用一个简单的字符串条删除
itertools

>>> struct.pack(">i", 456).lstrip(chr(0)) or chr(0)
'\x01\xc8'
甚至可以使用递归函数删除
struct

def to_bytes(n): 
    return ([chr(n & 255)] + to_bytes(n >> 8) if n > 0 else [])

"".join(reversed(to_bytes(456))) or chr(0)

如果您使用的是Python 2.7或更高版本,则可以使用
bit\u length
方法将长度四舍五入到下一个字节:

>>> i = 456
>>> bitstring.BitString(uint=i, length=(i.bit_length()+7)/8*8).bytes
'\x01\xc8'
否则,您可以只测试整个字节数,如果需要,可以在开始时用零字节填充:

>>> s = bitstring.BitString(hex=hex(i))
>>> ('0x0' + s if s.len%8 else s).bytes
'\x01\xc8'

我用一行重新编写了John Machins的第二个答案,以便在我的服务器上使用:

def bytestring(n):
    return ''.join([chr((n>>(i*8))&0xFF) for i in range(n.bit_length()/8,-1,-1)])

我发现第二种方法,使用位移位,对大数字和小数字都更快,而不仅仅是小数字。

这只需要对
int
有效,还是对
long
也有效?对于
long
,我忘了这一点。我将编辑这个问题。这可以在任何版本的Python中简单地完成,而不需要外部依赖项——在任何情况下,您都需要BYTEstring,而不是位字符串。
struct.pack
方法不起作用,因为
struct.unpack
需要固定长度。对于其他方法,您还需要一个反向函数(平凡)。这假设1字节等于8位。我不知道您是否可以对python语义做出这样的假设。第二种方法假设整数已经是big-endian。@ott:可以很安全地说,1字节等于8位,Python整数本身没有endianness-这只是它们如何存储或传输的问题(也就是说,如果你在到达这一步之前从某个地方错误地解包了
n
,这才是问题)。这两种方法在我看来都不错。实际上,它只是假设一个字节至少是8位,这是由C标准保证的,因此也是由C PyBytes类型保证的。(1)有人请给我看一台机器,它有一个非8位字节,不在博物馆里(比如Univac 110X(9位)或ICL 190X(6位)),并且有一个当前支持的Python实现(2)对于任何非负整数
x
x&0xFF
x%256
在C和Python中的含义完全相同,而与主机的端号无关。
bit\u length
似乎是一个干净的解决方案(尽管我在Debian上使用Python 2.6)
(i.bit_length()+7)/8*8
将长度四舍五入为可除以8的长度,对吗?endianness问题仍然存在。我发现了一个。因此,只剩下尾端问题。
uint
uintbe
的别名,因此尾端问题也得到了解决。这比需要的要困难一些,因此我添加了一个功能请求(),希望在下一个版本中,您可以只说
BitString(uintbe=456)。bytes
)我在使用大整数时遇到了一个错误。e、 g.big=244232342342432343422335353=>TypeError:“float”对象不能解释为整数