您拥有的代码仅将字母映射到一个位置。我们将重写它并创建一个rotate 函数。
代码
import string
import itertools as it
LOOKUP = {
**{x:i for i, x in enumerate(string.ascii_lowercase)},
**{x:i for i, x in enumerate(string.ascii_uppercase)}
}
def abc_position(letter):
"""Return the alpha position of a letter."""
return LOOKUP[letter]
def rotate(letter, shift=13):
"""Return a letter shifted some positions to the right; recycle at the end."""
iterable = it.cycle(string.ascii_lowercase)
start = it.dropwhile(lambda x: x != letter.casefold(), iterable)
# Advance the iterator
for i, x in zip(range(shift+1), start):
res = x
if letter.isupper():
return res.upper()
return res
测试
func = abc_position
assert func("a") == 0
assert func("A") == 0
assert func("c") == 2
assert func("z") == 25
func = rotate
assert func("h") == "u"
assert func("a", 0) == "a"
assert func("A", 0) == "A"
assert func("a", 2) == "c"
assert func("c", 3) == "f"
assert func("A", 2) == "C"
assert func("a", 26) == "a"
# Restart after "z"
assert func("z", 1) == "a"
assert func("Z", 1) == "A"
演示
>>> letter = input("Enter a letter: ")
Enter a letter: h
>>> rot = rotate(letter, 13)
>>> rot
'u'
>>> abc_position(rot)
20
这里我们将字母"h"旋转了13个位置,得到一个字母,然后确定这个结果字母在abc's的普通字符串中的位置。
详情
abc_position()
重写了这个函数来查找一个字母的位置。它合并了两个字典:
- 枚举小写 ascii 字母的方法
- 枚举大写 ascii 字母的方法
string 模块已经有了这个字母。
rotate()
这个函数只旋转小写字母;大写字母从小写位置转换而来。通过创建一个无限的小写字母cycle(迭代器)来旋转字母字符串。
- 循环首先前进到所需字母处的
start。这是通过删除所有看起来不像传入的字母来完成的。
- 然后它在循环中被推进一些等于
shift 的次数。循环只是消耗或向前移动迭代器的一种方式。我们只关心最后一个字母,而不是中间的那些。返回此字母,小写或大写。
由于返回的是字母(不是位置),您现在可以使用 abc_position() 函数找到它的正常位置。
替代品
其他旋转函数可以替代rotate():
import codecs
def rot13(letter):
return codecs.encode(letter, "rot13")
def rot13(letter):
table = str.maketrans(
"ABCDEFGHIJKLMabcdefghijklmNOPQRSTUVWXYZnopqrstuvwxyz",
"NOPQRSTUVWXYZnopqrstuvwxyzABCDEFGHIJKLMabcdefghijklm")
return str.translate(letter, table)
但是,这些选项仅限于 rot13,而 rotate() 可以移动任意数字。注意:rot26 会循环回到开头,例如rotate("a", 26) -> a.
另请参阅this post,了解如何制作真正的 rot13 密码。
另请参阅 itertools.cycle 和 itertools.dropwhile 上的文档。