9

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が、一見すると、必要なことを実行しているように見えました。)

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

これらの関数は、任意のサイズの long 数値をビッグ エンディアンの base64 表現に変換します。

于 2013-06-19T01:57:12.427 に答える
0

ここに役立つことがあります。を使用する代わりに、struct.pack()エンコードするバイトの文字列を作成し、その上で BASE64 エンコードを呼び出しています。私はデコードを書きませんでしたが、明らかに、デコードは同一のバイト文字列を復元でき、ループは元の値を復元できます。固定サイズの整数 (常に 128 ビットのように) が必要かどうかはわかりませんし、ビッグ エンディアンが必要かどうかもわかりません。

また、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 に答える