如何在Python中将长整型编码为Base64?
在Java中,我可以把一个BigInteger
编码成:
java.math.BigInteger bi = new java.math.BigInteger("65537L");
String encoded = Base64.encodeBytes(bi.toByteArray(), Base64.ENCODE|Base64.DONT_GUNZIP);
// result: 65537L encodes as "AQAB" in Base64
byte[] decoded = Base64.decode(encoded, Base64.DECODE|Base64.DONT_GUNZIP);
java.math.BigInteger back = new java.math.BigInteger(decoded);
在C#中:
System.Numerics.BigInteger bi = new System.Numerics.BigInteger("65537L");
string encoded = Convert.ToBase64(bi);
byte[] decoded = Convert.FromBase64String(encoded);
System.Numerics.BigInteger back = new System.Numerics.BigInteger(decoded);
我该如何在Python中把长整型数字编码成Base64格式的字符串呢?到目前为止,我尝试的结果和其他语言(比如Java和C#)的实现不一样,特别是我得到的Base64编码字符串长度更长。
import struct
encoded = struct.pack('I', (1<<16)+1).encode('base64')[:-1]
# produces a longer string, 'AQABAA==' instead of the expected 'AQAB'
当我使用这段Python代码生成Base64编码字符串时,结果在Java中解码后得到的整数是16777472
,而不是我预期的65537
。首先,我漏掉了什么呢?
其次,我需要手动弄清楚在struct.pack
中使用什么样的长度格式;如果我想编码一个很大的数字(大于(1<<64)-1
),那么'Q'
格式说明符就太短了,无法表示这个数字。这是否意味着我需要手动处理这个表示,还是说struct.pack
函数有一个未记录的格式说明符?(我并不一定要使用struct
,但乍一看它似乎能满足我的需求。)
5 个回答
1
这有点晚了,不过我想我也来凑个热闹:
def inttob64(n):
"""
Given an integer returns the base64 encoded version of it (no trailing ==)
"""
parts = []
while n:
parts.insert(0,n & limit)
n >>= 32
data = struct.pack('>' + 'L'*len(parts),*parts)
s = base64.urlsafe_b64encode(data).rstrip('=')
return s
def b64toint(s):
"""
Given a string with a base64 encoded value, return the integer representation
of it
"""
data = base64.urlsafe_b64decode(s + '==')
n = 0
while data:
n <<= 32
(toor,) = struct.unpack('>L',data[:4])
n |= toor & 0xffffffff
data = data[4:]
return n
这些函数可以把任意大小的长数字转换成大端格式的 base64 表示,或者从 base64 表示转换回来。
7
可以看看这个页面,里面讲的是如何把整数转换成base64格式,网址是这里。
import base64
import struct
def encode(n):
data = struct.pack('<Q', n).rstrip('\x00')
if len(data)==0:
data = '\x00'
s = base64.urlsafe_b64encode(data).rstrip('=')
return s
def decode(s):
data = base64.urlsafe_b64decode(s + '==')
n = struct.unpack('<Q', data + '\x00'* (8-len(data)) )
return n[0]
6
… 这个模块可以在Python值和用Python字符串表示的C结构之间进行转换。
因为C语言没有无限长度的整数,所以它没有处理这些整数的功能。
不过,自己写一个其实很简单。例如:
def pack_bigint(i):
b = bytearray()
while i:
b.append(i & 0xFF)
i >>= 8
return b
或者:
def pack_bigint(i):
bl = (i.bit_length() + 7) // 8
fmt = '<{}B'.format(bl)
# ...
还有其他类似的方式。
当然,你还需要一个unpack
函数,就像评论里jbatista提到的那样:
def unpack_bigint(b):
b = bytearray(b) # in case you're passing in a bytes/str
return sum((1 << (bi*8)) * bb for (bi, bb) in enumerate(b))