2

参考: 有没有更快的方法将数字转换为名称?

在上面提到的问题中,找到了将数字变为名称的解决方案。这个问题正好相反。如何将名称转换回数字?到目前为止,这就是我所拥有的:

>>> import string
>>> HEAD_CHAR = ''.join(sorted(string.ascii_letters + '_'))
>>> TAIL_CHAR = ''.join(sorted(string.digits + HEAD_CHAR))
>>> HEAD_BASE, TAIL_BASE = len(HEAD_CHAR), len(TAIL_CHAR)
>>> def number_to_name(number):
        "Convert a number into a valid identifier."
        if number < HEAD_BASE:
            return HEAD_CHAR[number]
        q, r = divmod(number - HEAD_BASE, TAIL_BASE)
        return number_to_name(q) + TAIL_CHAR[r]

>>> [number_to_name(n) for n in range(117)]
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '_', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A0', 'A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9', 'AA', 'AB', 'AC', 'AD', 'AE', 'AF', 'AG', 'AH', 'AI', 'AJ', 'AK', 'AL', 'AM', 'AN', 'AO', 'AP', 'AQ', 'AR', 'AS', 'AT', 'AU', 'AV', 'AW', 'AX', 'AY', 'AZ', 'A_', 'Aa', 'Ab', 'Ac', 'Ad', 'Ae', 'Af', 'Ag', 'Ah', 'Ai', 'Aj', 'Ak', 'Al', 'Am', 'An', 'Ao', 'Ap', 'Aq', 'Ar', 'As', 'At', 'Au', 'Av', 'Aw', 'Ax', 'Ay', 'Az', 'B0']
>>> def name_to_number(name):
    assert name, 'Name must exist!'
    head, *tail = name
    number = HEAD_CHAR.index(head)
    for position, char in enumerate(tail):
        if position:
            number *= TAIL_BASE
        else:
            number += HEAD_BASE
        number += TAIL_CHAR.index(char)
    return number

>>> [name_to_number(number_to_name(n)) for n in range(117)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 54]

该函数number_to_name运行良好,name_to_number一直运行到数字 116。此时,该函数返回 54。有人看到代码的问题吗?


基于递归答案的解决方案:

import string

HEAD_CHAR = ''.join(sorted(string.ascii_letters + '_'))
TAIL_CHAR = ''.join(sorted(string.digits + HEAD_CHAR))
HEAD_BASE, TAIL_BASE = len(HEAD_CHAR), len(TAIL_CHAR)

def name_to_number(name):
    if not name.isidentifier():
        raise ValueError('Name must be a Python identifier!')
    head, *tail = name
    number = HEAD_CHAR.index(head)
    for char in tail:
        number *= TAIL_BASE
        number += TAIL_CHAR.index(char)
    return number + sum(HEAD_BASE * TAIL_BASE ** p for p in range(len(tail)))
4

1 回答 1

1

不幸的是,这些标识符不屈服于传统的常量基本编码技术。例如,“A”的作用类似于零,但前导的“A”会改变值。在正常数字系统中,前导零不会。可能有多种方法,但我选择了一种方法来计算具有较少数字的标识符的总数,并从那里开始。

def name_to_number(name):
    assert name, 'Name must exist!'

    skipped = sum(HEAD_BASE * TAIL_BASE ** i for i in range(len(name) - 1))
    val = reduce(
        lambda a,b: a * TAIL_BASE + TAIL_CHAR.index(b), 
        name[1:], 
        HEAD_CHAR.index(name[0]))
    return val + skipped
于 2013-06-12T23:43:53.227 回答