python中可以表示任意大的整数_Python:紧凑且可逆地将大整数编码为具有可...

此答案部分是由Erik A.的不同评论(例如this答案)推动的.首先将整数紧凑地转换为字节,然后将字节编码为变量base.

from typing import Callable, Optional

import base64

class IntBaseEncoder:

"""Reversibly encode an unsigned or signed integer into a customizable encoding of a variable or fixed length."""

# Ref: https://stackoverflow.com/a/54152763/

def __init__(self, encoding: str, *, bits: Optional[int] = None, signed: bool = False):

"""

:param encoder: Name of encoding from base64 module, e.g. b64, urlsafe_b64, b32, b16, etc.

:param bits: Max bit length of int which is to be encoded. If specified, the encoding is of a fixed length,

otherwise of a variable length.

:param signed: If True, integers are considered signed, otherwise unsigned.

"""

self._decoder: Callable[[bytes], bytes] = getattr(base64, f'{encoding}decode')

self._encoder: Callable[[bytes], bytes] = getattr(base64, f'{encoding}encode')

self.signed: bool = signed

self.bytes_length: Optional[int] = bits and self._bytes_length(2 ** bits - 1)

def _bytes_length(self, i: int) -> int:

return (i.bit_length() + 7 + self.signed) // 8

def encode(self, i: int) -> bytes:

length = self.bytes_length or self._bytes_length(i)

i_bytes = i.to_bytes(length, byteorder='big', signed=self.signed)

return self._encoder(i_bytes)

def decode(self, b64: bytes) -> int:

i_bytes = self._decoder(b64)

return int.from_bytes(i_bytes, byteorder='big', signed=self.signed)

# Tests:

import unittest

class TestIntBaseEncoder(unittest.TestCase):

ENCODINGS = ('b85', 'b64', 'urlsafe_b64', 'b32', 'b16')

def test_unsigned_with_variable_length(self):

for encoding in self.ENCODINGS:

encoder = IntBaseEncoder(encoding)

previous_length = 0

for i in range(1234):

encoded = encoder.encode(i)

self.assertGreaterEqual(len(encoded), previous_length)

self.assertEqual(i, encoder.decode(encoded))

def test_signed_with_variable_length(self):

for encoding in self.ENCODINGS:

encoder = IntBaseEncoder(encoding, signed=True)

previous_length = 0

for i in range(-1234, 1234):

encoded = encoder.encode(i)

self.assertGreaterEqual(len(encoded), previous_length)

self.assertEqual(i, encoder.decode(encoded))

def test_unsigned_with_fixed_length(self):

for encoding in self.ENCODINGS:

for maxint in range(257):

encoder = IntBaseEncoder(encoding, bits=maxint.bit_length())

maxlen = len(encoder.encode(maxint))

for i in range(maxint + 1):

encoded = encoder.encode(i)

self.assertEqual(len(encoded), maxlen)

self.assertEqual(i, encoder.decode(encoded))

def test_signed_with_fixed_length(self):

for encoding in self.ENCODINGS:

for maxint in range(257):

encoder = IntBaseEncoder(encoding, bits=maxint.bit_length(), signed=True)

maxlen = len(encoder.encode(maxint))

for i in range(-maxint, maxint + 1):

encoded = encoder.encode(i)

self.assertEqual(len(encoded), maxlen)

self.assertEqual(i, encoder.decode(encoded))

if __name__ == '__main__':

unittest.main()

如果将输出用作文件名,则使用编码'urlsafe_b64'甚至“ b16”初始化编码器是更安全的选择.

用法示例:

# Variable length encoding

>>> encoder = IntBaseEncoder('urlsafe_b64')

>>> encoder.encode(12345)

b'MDk='

>>> encoder.decode(_)

12345

# Fixed length encoding

>>> encoder = IntBaseEncoder('b16', bits=32)

>>> encoder.encode(12345)

b'00003039'

>>> encoder.encode(123456789)

b'075BCD15'

>>> encoder.decode(_)

123456789

# Signed

encoder = IntBaseEncoder('b32', signed=True)

encoder.encode(-12345)

b'Z7DQ===='

encoder.decode(_)

-12345

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值