9

在 Java 中,我可以将 a 编码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 编码的字符串?到目前为止,我所尝试的结果与其他语言的实现不同(到目前为止,我已经在 J​​ava 和 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,但乍一看它似乎可以满足我的需要。)

4

4 回答 4

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]
于 2013-02-08T01:28:32.693 回答
5

struct模块:_

... 执行 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))
于 2013-02-08T02:17:53.437 回答
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 表示。

于 2013-06-19T01:57:12.427 回答
0

这可能会有所帮助。我没有使用struct.pack()我构建一串字节进行编码,然后在其上调用 BASE64 编码。我没有编写解码器,但显然解码器可以恢复相同的字节串,并且循环可以恢复原始值。我不知道你是否需要固定大小的整数(总是 128 位),我不知道你是否需要 Big Endian,所以我把解码器留给了你。

此外,encode64()并且decode64()来自@msc 的答案,但已修改为可以使用。

import base64
import struct

def encode64(n):
  data = struct.pack('<Q', n).rstrip('\x00')
  if len(data)==0:
    data = '\x00'
  s = base64.urlsafe_b64encode(data).rstrip('=')
  return s

def decode64(s):
  data = base64.urlsafe_b64decode(s + '==')
  n = struct.unpack('<Q', data + '\x00'* (8-len(data)) )
  return n[0]

def encode(n, big_endian=False):
    lst = []
    while True:
        n, lsb = divmod(n, 0x100)
        lst.append(chr(lsb))
        if not n:
            break
    if big_endian:
        # I have not tested Big Endian mode, and it may need to have
        # some initial zero bytes prepended; like, if the integer is
        # supposed to be a 128-bit integer, and you encode a 1, you
        # would need this to have 15 leading zero bytes.
        initial_zero_bytes = '\x00' * 2
        data = initial_zero_bytes + ''.join(reversed(lst))
    else:
        data = ''.join(lst)
    s = base64.urlsafe_b64encode(data).rstrip('=')
    return s

print encode(1234567890098765432112345678900987654321)
于 2013-02-08T02:49:12.837 回答