【问题标题】:How do I represent a string as a number?如何将字符串表示为数字?
【发布时间】:2017-06-30 03:50:34
【问题描述】:

我需要将一个字符串表示为一个数字,但是它有 8928313 个字符长,请注意这个字符串可以包含的不仅仅是字母,我还必须能够有效地将它转换回来。我当前(太慢)的代码如下所示:

alpha = 'abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ,.?!@()+-=[]/*1234567890^*{}\'"$\\&#;|%<>:`~_'
alphaLeng = len(alpha)
def letterNumber(letters):
    letters = str(letters)
    cof = 1
    nr = 0
    for i in range(len(letters)):
        nr += cof*alpha.find(letters[i])
        cof *= alphaLeng
        print(i,'        ',len(letters))
    return str(nr)

【问题讨论】:

  • 请注意,这段代码运行良好,只是太慢了
  • 我严重质疑为什么您需要一个精度约为 8 MB 的数字。最终,字符串和数字都是字节。字符串是你想要的数据类型。
  • 您使用的是 Python 3 还是 Python 2?我假设你没有使用 both

标签: python python-2.7 python-3.x numbers


【解决方案1】:

好的,既然其他人给出的答案很糟糕,我会介入。

  1. 你不应该这样做。
  2. 你不应该这样做。
  3. 整数和字符数组最终是同一个东西:字节。您可以以相同的方式访问这些值。
  4. 大多数数字表示的上限为 8 个字节(64 位)。您正在查看 8 MB,即最大整数表示的 100 万倍。你不应该这样做。真的。
  5. 您不应该这样做。您的号码将只是一个自定义的、巨大的号码类型,在后台是相同的。
  6. 如果您真的想要这样做,尽管有上述所有原因,这里是...

代码

def lshift(a, b):
    # bitwise left shift 8
    return (a << (8 * b))

def string_to_int(data):
    sum_ = 0
    r = range(len(data)-1, -1, -1)
    for a, b in zip(bytearray(data), r):
        sum_ += lshift(a, b)
    return sum_;

不要这样做

说明

字符本质上是字节:它们可以以不同的方式编码,但最终您可以在给定的编码中将它们视为字节序列。为了将它们转换为数字,我们可以将它们在序列中的位置左移 8 位,创建一个唯一的数字。 r,范围值,倒序为位置:第4个元素需要左移24字节(3*8)等

在获取范围并将我们的数据转换为 8 位整数后,我们可以转换数据并求和,从而为我们提供唯一标识符。它将与原始数字按字节(或反向字节顺序)相同,但只是“作为数字”。这完全是徒劳的。不要这样做。

性能

任何性能都会被您无缘无故地创建相同对象的事实所抵消,但此解决方案的性能相当不错。

1,000 个元素大约需要 486 微秒,10,000 个元素大约需要 20.5 毫秒,而 100,000 个元素大约需要 1.5 秒。它会起作用,但你不应该这样做。这意味着它被缩放为 O(n**2),这可能是由于每次整数大小变大时重新分配数据的内存开销。这可能需要大约 4 小时来处理所有 8e6 元素(14365 秒,计算将低阶数据拟合到 ax**2+bx+c)。请记住,这一切都是为了获得与原始数据相同的字节表示。

无用

请记住,根据目前的估计,整个宇宙中大约有 1e78 到 1e82 个原子。这是〜2 ^ 275。您的值将能够表示 2^71426504,或者大约是表示宇宙中每个原子所需的位数的 260,000 倍。你不需要这样的号码。你永远不会

【讨论】:

  • “字符本质上是 8 位整数”嗯,这取决于。它们可以是 unicode 代码点。在这种情况下,它们由 1-4 个字节表示。
  • @juanpa.arrivillaga 可以用 8 位整数表示,使用 UTF-8。我从未指定编码。为此,即使是编码为 UTF-32 的代码点也可以同样工作。无论如何,OP 的整个想法都很糟糕。
  • 是的,我明白了。我只是认为该评论有点模糊和误导。换句话说,它坚持 Cish “字符是字节”的抽象。我毫不怀疑您理解这些微妙之处,但阅读您的答案的其他人可能不清楚。字符编码只是人们认为他们可以在不真正理解的情况下逃脱的那些事情之一。
【解决方案2】:

如果只有 ANSII 字符。您可以使用ord()chr()

built-in functions

【讨论】:

  • ordchr 适用于所有字符。但除此之外,我相信这是最合理的答案。
  • 对于 python 3,这些函数适用于所有 Unicode 字符。但是python 2只支持ANSII。
  • 你是对的。我对代码支持不是很熟悉。我刚试过ord('x'),其中x是python 2中的中文单词,但出现错误。但是错误实际上来自字符文字,应该是ord(u'x')
  • 对,因为在 Python 2 中,ord('x') 其中x 是一些中文单词,将是一些多字节序列,因此'x' 的长度将>1。如果您在前面加上u"x",那么u''x" 将是一个单元素unicode 代码点序列,长度为1。
【解决方案3】:

您可以执行多种优化。例如,find 方法需要在您的字符串中搜索相应的字母。字典会更快。更快的可能是(基准!)chr 函数(如果你对字母顺序不太挑剔的话)和 ord 函数来反转chr。但是,如果您对排序不挑剔,那么如果您不需要以任何特定格式显示该值,那么您最好只在字符串中添加 NULL 并将其视为内存中的大二进制数。

您可以通过迭代字符而不是字符索引来获得一些加速。如果您使用的是 Python 2,那么大的 range 会很慢,因为需要生成一个列表(使用 xrange 而不是 Python 2); Python 3 使用了生成器,所以更好。

你的print 函数会减慢输出速度,尤其是当你输出到 tty 时。

一个大数字库也可以让你加速:Handling big numbers in code

【讨论】:

  • 谢谢,我会努力做字典的。打印只是为了调试目的,很快就会被删除。使用 Python 3.6,还有其他可能的优化吗?
【解决方案4】:

您的alpha.find() 函数需要在每个循环中遍历alpha

您可能可以通过使用dict 来加快速度,因为字典查找是 O(1):

alpha = 'abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ,.?!@()+-=[]/*1234567890^*{}\'"$\\&#;|%<>:`~_'

alpha_dict = { letter: index for index, letter in enumerate(alpha)}
print(alpha.find('$'))
# 83
print(alpha_dict['$'])
# 83

【讨论】:

    猜你喜欢
    • 2015-11-14
    • 2016-06-04
    • 2018-04-01
    • 2017-08-17
    • 1970-01-01
    • 2016-03-09
    • 1970-01-01
    • 2020-12-03
    • 1970-01-01
    相关资源
    最近更新 更多