众所周知,计算机使用数字。我正在输入此文本,服务器会输出一个数字,当您想要读取它时,您将从服务器获取文本。
我怎么能独自完成这个?
我想用自己的算法加密某些东西,我的算法可以很好地处理整数,但现在我想加密一个字符串,我不知道如何将Unicode字符串转换为整数,反之亦然。
我正在使用Python 3.有没有人知道我的问题的优雅解决方案?
答案 0 :(得分:12)
您正在寻找ord()
function,我认为:
>>> ord('a')
97
>>> ord('\u00c2')
192
这将为您提供Unicode代码点的整数。
要转换整个字符集,请使用列表解析:
>>> [ord(c) for c in 'Hello World!']
[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]
相反的是chr()
function:
>>> chr(97)
'a'
>>> chr(193)
'Á'
请注意,当您加密最终解密文本时,通常将文本编码为带有character encoding的二进制表示。 Unicode文本可以使用不同的编码进行编码,具有不同的优点和缺点。这些天是Unicode文本UTF-8最常用的编码,但其他编码存在。
在Python 3中,二进制数据在bytes
object中表示,您使用str.encode()
method将文本编码为字节,然后使用bytes.decode()
返回:
>>> 'Hello World!'.encode('utf8')
b'Hello World!'
>>> b'Hello World!'.decode('utf8')
'Hello World!'
bytes
值实际上只是序列,如列表,元组和字符串,但由0-255的整数组成:
>>> list('Hello World!'.encode('utf8'))
[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]
就个人而言,在加密时,您希望对结果字节进行编码和加密。
如果所有这些看起来势不可挡或难以理解,那么这些关于Unicode和字符编码的文章可能会有所帮助:
答案 1 :(得分:11)
将Unicode字符串转换为数字的常用方法是将其转换为字节序列。 Unicode字符是纯抽象的,每个字符都有自己的编号;但是,有更多方法可以将数字转换为字节流。可能最通用的方法是将字符串编码为UTF-8编码。您可以选择多种方法从中获取整数。这是一个(我从Ivella借来了很好的字符串 - 我希望里面没有坏词:):
Python 3.2.1 (default, Jul 10 2011, 20:02:51) [MSC v.1500 64 bit (AMD64)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> s = "Hello, World, عالَم, ދުނިޔެ, जगत, 世界"
>>> b = s.encode('utf-8')
>>> b
b'Hello, World, \xd8\xb9\xd8\xa7\xd9\x84\xd9\x8e\xd9\x85, \xde\x8b\xde\xaa\xde\x82\xde\xa8\xde\x94\xde\xac, \xe0\xa4\x9c\xe0\xa4\x97\xe0\xa4\xa4, \xe4\xb8\x96\xe7\x95\x8c'
现在我们有字节序列,其中数字从128到255的那些显示为十六进制编码的转义序列。让我们将所有字节转换为十六进制代码作为字节串。
>>> import binascii
>>> h = binascii.hexlify(b)
>>> h
b'48656c6c6f2c20576f726c642c20d8b9d8a7d984d98ed9852c20de8bdeaade82dea8de94deac2c20e0a49ce0a497e0a4a42c20e4b896e7958c'
我们可以将它看作是以十六进制表示法编写的大数字(如文本)。 int
允许我们将它转换为抽象数字 - 在打印时 - 更通常转换为十进制表示法。
>>> i = int(h, 16)
>>> i
52620351230730152682202055464811384749235956796562762198329268116226267262806875102376740945811764490696968801603738907493997296927348108
现在您可以将其存储为数字,对其进行加密(尽管更常见的是加密较早的字节序列),然后将其转换回整数。请注意,没有多少语言(可能没有数据库)能够处理大整数。
让我们回到原来的字符串。首先将其转换为十六进制表示(字符串)。
>>> h2 = hex(i)
>>> h2
'0x48656c6c6f2c20576f726c642c20d8b9d8a7d984d98ed9852c20de8bdeaade82dea8de94deac2c20e0a49ce0a497e0a4a42c20e4b896e7958c'
>>> h3 = h2[2:] # remove the 0x from the beginning
>>> h3
'48656c6c6f2c20576f726c642c20d8b9d8a7d984d98ed9852c20de8bdeaade82dea8de94deac2c20e0a49ce0a497e0a4a42c20e4b896e7958c'
>>> type(h3)
<class 'str'>
我们必须删除0x
,因为它只表示其余的是表示数字的十六进制字符。请注意,h3
属于str
类型。正如我们在Python 3中所见(见顶部),str
表示Unicode字符串。下一步是将六进制数字对转换回字节。我们试试unhexlify()
:
>>> binascii.unhexlify(h3)
Traceback (most recent call last):
File "<pyshell#16>", line 1, in <module>
binascii.unhexlify(h3)
TypeError: 'str' does not support the buffer interface
糟糕!它只接受字节串。然后,将Unicode中的每个hexa数字编码为bytestring中的hexa数字。要走的路是编码;然而,编码为ASCII是微不足道的。
>>> b2 = h3.encode('ascii') # character by character; subset of ascii only
>>> b2
b'48656c6c6f2c20576f726c642c20d8b9d8a7d984d98ed9852c20de8bdeaade82dea8de94deac2c20e0a49ce0a497e0a4a42c20e4b896e7958c'
>>> b3 = binascii.unhexlify(b2)
>>> b3
b'Hello, World, \xd8\xb9\xd8\xa7\xd9\x84\xd9\x8e\xd9\x85, \xde\x8b\xde\xaa\xde\x82\xde\xa8\xde\x94\xde\xac, \xe0\xa4\x9c\xe0\xa4\x97\xe0\xa4\xa4, \xe4\xb8\x96\xe7\x95\x8c'
现在我们有与第一个.encode('utf-8')
之后相似的字节串。让我们使用逆操作 - 从UTF-8解码。我们应该得到与我们开始时相同的Unicode字符串。
>>> s2 = b3.decode('utf-8')
>>> s2
'Hello, World, عالَم, ދުނިޔެ, जगत, 世界'
>>> s == s2 # is the original equal to the result?
True
:)
答案 2 :(得分:5)
来自python的文档:
binascii module包含许多转换方法 二进制和各种ASCII编码的二进制表示。
例如,您可以使用binascii.hexlify
获取二进制字符串“LOL”的十六进制表示形式,并通过int内置函数将其转换为整数:
>>> binascii.hexlify(b"LOL")
b'4c4f4c'
>>> int(binascii.hexlify(b"LOL"), 16)
5001036
由于您需要将此应用于unicode字符串,因此首先需要将它们编码为二进制字符串。您可以使用方法str.encode
来实现此目的:
>>> int(binascii.hexlify("fiŝaĵo".encode("utf-8")), 16)
7379646744164087151
就是这样。
反之亦然,您需要反转每一步。首先以十六进制表示形式将整数转换为二进制字符串(您可以使用format(int, "x")
然后对其进行编码),将ascii中的十六进制转换为binascii.unhexlify
,最后解码为utf-8:
>>> binascii.unhexlify(format(7379646744164087151, "x").encode("utf-8")).decode("utf-8")
'fiŝaĵo'
这是一个循序渐进的解释,如果你真的会使用这个设施,那么以功能的形式安排它们是个好主意。
答案 3 :(得分:1)
在Martijn Pieters给出的解决方案的基础上,你可以使你的字符串成为一个庞大的数字,Python 3可以很好地处理,因为它的int类型是任意大的(不是“计算机如何工作”,请参阅我的评论你的问题)。
给出字符数字代码列表:
>>> a = [ord(c) for c in 'Hello World!']
>>> print(a)
[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]
从维基百科的Unicode页面知道最大的unicode字符数是10FFFF(十六进制),你可以这样做:
def numfy(s):
number = 0
for e in [ord(c) for c in s]:
number = (number * 0x110000) + e
return number
def denumfy(number):
l = []
while(number != 0):
l.append(chr(number % 0x110000))
number = number // 0x110000
return ''.join(reversed(l))
因此:
>>> a = numfy("Hello, World, عالَم, ދުނިޔެ, जगत, 世界")
>>> a
31611336900126021[...]08666956
>>> denumfy(a)
'Hello, World, عالَم, ދުނިޔެ, जगत, 世界'
此0x110000(从10FFFF + 1)是不同的预见Unicode字符数(1114112,十进制)。如果你确定你只使用英文字母,你可以在这里使用128,如果你使用一些带有重音的拉丁语,使用256是安全的。无论哪种方式你的数字都会小得多,但它将无法使用表示每个Unicode字符。
答案 4 :(得分:-1)
这会将每个字符转换为数字......
s="hello \u2020"
print [ord(c) for c in s]