如何将Python标识符转换为数字? [英] How can you convert a Python identifier into a number?

查看:132
本文介绍了如何将Python标识符转换为数字?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

In the question referenced above, a solution was found for turning a numbe into a name. This question asks just the opposite. How can you convert a name back into a number? So far, this is what I have:

>>> 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.有人看到代码的问题了吗?

The function number_to_name works perfectly, and name_to_number works up until it gets to number 116. At that point, the function returns 54 instead. Does anyone see the code's problem?

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

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)))

推荐答案

不幸的是,这些标识符不能屈服于传统的常量基础编码技术.例如,"A"的作用类似于零,但是前导"A"会更改值.在普通数字系统中,前导零不会.可能有多种方法,但我决定使用一种方法来计算位数较少的标识符总数,然后从中开始.

Unfortunately, these identifiers don't yield to traditional constant base encoding techniques. For example "A" acts like a zero, but leading "A"s change the value. In normal number systems leading zeroes do not. There could be multiple approaches, but I settled on one that calculates the total number of identifiers with fewer digits, and starts from that.

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

这篇关于如何将Python标识符转换为数字?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆