我想将字符串(由字母数字字符组成)转换为整数,然后将该整数转换回字符串:
string --> int --> string
换句话说,我想用一个整数表示字母数字字符串。
我找到了一个可行的解决方案,已将其包含在答案中,但我认为这不是最佳解决方案,并且我对其他想法/方法也很感兴趣。
请不要仅因为已经存在许多类似的问题就将其标记为重复项,所以我特别希望有一种简单的方法将字符串转换为整数,反之亦然。
这应该适用于包含字母数字字符的字符串,即包含数字和字母的字符串。
答案 0 :(得分:2)
这是我到目前为止所拥有的:
字符串->字节
mBytes = m.encode("utf-8")
bytes-> int
mInt = int.from_bytes(mBytes, byteorder="big")
int->字节
mBytes = mInt.to_bytes(((mInt.bit_length() + 7) // 8), byteorder="big")
字节->字符串
m = mBytes.decode("utf-8")
尝试一下:
m = "test123"
mBytes = m.encode("utf-8")
mInt = int.from_bytes(mBytes, byteorder="big")
mBytes2 = mInt.to_bytes(((mInt.bit_length() + 7) // 8), byteorder="big")
m2 = mBytes2.decode("utf-8")
print(m == m2)
以下是与上述相同的可重用版本:
class BytesIntEncoder:
@staticmethod
def encode(b: bytes) -> int:
return int.from_bytes(b, byteorder='big')
@staticmethod
def decode(i: int) -> bytes:
return i.to_bytes(((i.bit_length() + 7) // 8), byteorder='big')
如果您使用的是Python <3.6,请删除可选的类型注释。
测试:
>>> s = 'Test123'
>>> b = s.encode()
>>> b
b'Test123'
>>> BytesIntEncoder.encode(b)
23755444588720691
>>> BytesIntEncoder.decode(_)
b'Test123'
>>> _.decode()
'Test123'
答案 1 :(得分:1)
回想一下,可以将字符串编码为字节,然后可以将其编码为整数。然后可以反转编码以获取字节,后跟原始字符串。
此编码器使用binascii
产生与charel-f答案相同的相同整数编码。我知道它是相同的,因为我已经对其进行了广泛的测试。
信用:this answer。
from binascii import hexlify, unhexlify
class BytesIntEncoder:
@staticmethod
def encode(b: bytes) -> int:
return int(hexlify(b), 16) if b != b'' else 0
@staticmethod
def decode(i: int) -> int:
return unhexlify('%x' % i) if i != 0 else b''
如果您使用的是Python <3.6,请删除可选的类型注释。
快速测试:
>>> s = 'Test123'
>>> b = s.encode()
>>> b
b'Test123'
>>> BytesIntEncoder.encode(b)
23755444588720691
>>> BytesIntEncoder.decode(_)
b'Test123'
>>> _.decode()
'Test123'
答案 2 :(得分:1)
假设字符集仅是字母数字,即a-z A-Z 0-9,则每个字符需要6位。因此,从理论上讲,使用8位字节编码是对内存的低效率使用。
此答案将输入字节转换为6位整数序列。它使用按位运算将这些小整数编码为一个大整数。 sys.getsizeof
衡量这是否真正转化为实际的存储效率,并且对于较大的字符串更有可能。
此实现可自定义编码以选择字符集。例如,如果您仅使用string.ascii_lowercase
(5位)而不是string.ascii_uppercase + string.digits
(6位),则编码将相应地有效。
还包括单元测试。
import string
class BytesIntEncoder:
def __init__(self, chars: bytes = (string.ascii_letters + string.digits).encode()):
num_chars = len(chars)
translation = ''.join(chr(i) for i in range(1, num_chars + 1)).encode()
self._translation_table = bytes.maketrans(chars, translation)
self._reverse_translation_table = bytes.maketrans(translation, chars)
self._num_bits_per_char = (num_chars + 1).bit_length()
def encode(self, chars: bytes) -> int:
num_bits_per_char = self._num_bits_per_char
output, bit_idx = 0, 0
for chr_idx in chars.translate(self._translation_table):
output |= (chr_idx << bit_idx)
bit_idx += num_bits_per_char
return output
def decode(self, i: int) -> bytes:
maxint = (2 ** self._num_bits_per_char) - 1
output = bytes(((i >> offset) & maxint) for offset in range(0, i.bit_length(), self._num_bits_per_char))
return output.translate(self._reverse_translation_table)
# Test
import itertools
import random
import unittest
class TestBytesIntEncoder(unittest.TestCase):
chars = string.ascii_letters + string.digits
encoder = BytesIntEncoder(chars.encode())
def _test_encoding(self, b_in: bytes):
i = self.encoder.encode(b_in)
self.assertIsInstance(i, int)
b_out = self.encoder.decode(i)
self.assertIsInstance(b_out, bytes)
self.assertEqual(b_in, b_out)
# print(b_in, i)
def test_thoroughly_with_small_str(self):
for s_len in range(4):
for s in itertools.combinations_with_replacement(self.chars, s_len):
s = ''.join(s)
b_in = s.encode()
self._test_encoding(b_in)
def test_randomly_with_large_str(self):
for s_len in range(256):
num_samples = {s_len <= 16: 2 ** s_len,
16 < s_len <= 32: s_len ** 2,
s_len > 32: s_len * 2,
s_len > 64: s_len,
s_len > 128: 2}[True]
# print(s_len, num_samples)
for _ in range(num_samples):
b_in = ''.join(random.choices(self.chars, k=s_len)).encode()
self._test_encoding(b_in)
if __name__ == '__main__':
unittest.main()
用法示例:
>>> encoder = BytesIntEncoder()
>>> s = 'Test123'
>>> b = s.encode()
>>> b
b'Test123'
>>> encoder.encode(b)
3908257788270
>>> encoder.decode(_)
b'Test123'
答案 3 :(得分:1)
所以我需要根据数字传送字典, 它可能看起来有些丑陋,但是它的效率很高,即每个字符(英文字母)恰好是2个数字,但是它能够传输任何类型的unicode字符
import json
myDict = {
"le key": "le Valueue",
2 : {
"heya": 1234569,
"3": 4
},
'Α α, Β β, Γ γ' : 'שלום'
}
def convertDictToNum(toBeConverted):
return int(''.join([(lambda c: c if len(c) ==2 else '0'+c )(str(ord(c) - 26)) for c in str(json.dumps(toBeConverted))]))
def loadDictFromNum(toBeDecoded):
toBeDecoded = str(toBeDecoded)
return json.loads(''.join([chr(int(toBeDecoded[cut:cut + 2]) + 26) for cut in range(0, len(toBeDecoded), 2)]))
numbersDict = convertDictToNum(myDict)
print(numbersDict)
# 9708827506817595083206088....
recoveredDict = loadDictFromNum(numbersDict)
print(recoveredDict)
# {'le key': 'le Valueue', '2': {'heya': 1234569, '3': 4}, 'Α α, Β β, Γ γ': 'שלום'}