13

众所周知,计算机处理数字。我现在正在输入此文本,服务器从中生成一个数字,当您想阅读它时,您将从服务器获取文本。

我怎么能自己做到这一点?

我想用我自己的算法加密一些东西,我的算法适用于整数,但现在我想加密一个字符串,我不知道如何将 Unicode 字符串转换为整数,反之亦然。

我正在使用 Python 3。有没有人知道我的问题的优雅解决方案?

4

5 回答 5

17

您正在寻找ord()功能,我认为:

>>> 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()函数是:

>>> chr(97)
'a'
>>> chr(193)
'Á'

请注意,当您加密结束解密文本时,您通常将文本编码为具有字符编码的二进制表示。Unicode 文本可以用不同的编码进行编码,具有不同的优点和缺点。如今,Unicode 文本最常用的编码是UTF-8,但也有其他的。

在 Python 3 中,二进制数据在bytesobject中表示,您可以使用该方法将文本编码为字节,然后使用以下str.encode()方法返回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 和字符编码的文章可以提供帮助:

于 2012-09-27T16:12:23.917 回答
12

将 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因为它只说其余的是代表数字的十六进制字符。请注意,h3str类型。正如我们在 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 中的每个十六进制数字编码为字节串中的十六进制数字。要走的路是编码;但是,编码为 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

:)

于 2012-09-27T18:32:26.260 回答
8

来自python的文档:

binascii模块包含许多在二进制和各种 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")然后对其进行编码),将十六进制转换为 asciibinascii.unhexlify并最后解码为 utf-8:

>>> binascii.unhexlify(format(7379646744164087151, "x").encode("utf-8")).decode("utf-8")
'fiŝaĵo'

这是一个循序渐进的解释,如果您真的要使用这些工具,最好以函数的形式排列它们。

于 2012-09-27T18:45:57.537 回答
2

在 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上的 Wikipedia 页面,最大的 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 字符。

于 2012-09-27T17:24:32.437 回答
-1

这会将每个字符转换为数字...

s="hello \u2020"
print [ord(c) for c in s]
于 2012-09-27T16:15:38.663 回答