Python中的移位密码:使用ord函数时出现错误

3
我希望把字符串中的每个字符替换为另一个字符,新字符在字母表中向后移动。以下是示例中移动2个字符的情况,因此 a -> c,b -> d,以此类推。
我正在尝试使用正则表达式和sub函数来完成这个任务,但是我遇到了错误。
这是我目前的代码:
p = re.compile(r'(\w)')
test = p.sub(chr(ord('\\1') + 2), text)
print test

其中变量text是一个输入字符串。

我遇到了这个错误:

TypeError: ord()期望一个字符,但发现长度为2的字符串

我认为问题在于ord函数被调用在字面字符串"\ 1"上,而不是正则表达式匹配的\ w字符。正确的方法是什么?


1
你没有理由使用正则表达式; 正则表达式用于检测子字符串(通常带有特殊结构),但是你可以已经不使用正则表达式提取单个字符的子字符串:只需使用[c for c in string]。无论如何,我已经提供了一个解决方案(它不使用正则表达式)。 - ninjagecko
我选择使用正则表达式的原因是因为我只想转换“单词”字符,而不确定如何使用推导式实现这一点。(如果你没看出来,我正在学习Python) - Joe
字符串可能包含空格和标点符号。这些字符不应该被移动,但任何数字或字母都应该被移动。对于歧义表示抱歉。 原问题有几个很好的答案。如果可以的话,我会点赞。 - Joe
Joe:请注意,在大多数正则表达式解析器中,\w 的意思是 [A-Za-z0-9_] - ninjagecko
[c for c in string] 是我的第一个想法,但我不知道如何进行模式匹配,以便只移动 [A-Za-z0-9] 中的值。我也没有意识到 \w 包括 '_'。感谢您的帮助。 - Joe
4个回答

4

这样是行不通的。Python首先运行chr(ord('\\') + 2,然后将结果传递给p.sub

你需要将其放在一个单独的函数中或使用匿名函数(lambda):

p = re.compile(r'(\w)')
test = p.sub(lambda m: chr(ord(m.group(1)) + 2), text)
print test

或者更好的方法是使用 maketrans 而不是正则表达式:
import string

shift = 2

t = string.maketrans(string.ascii_lowercase, string.ascii_lowercase[shift:] +
                                             string.ascii_lowercase[:shift])
string.translate(text, t)

这将无法移动,例如将 'z' 移动到 'a'。由于提问者也犯了同样的错误,所以不会有人投反对票。 - ninjagecko
1
很好的观点,@ninjagecko,我会保留它以演示使用sub回调函数。无论如何,他都应该使用maketrans - Rob Wouters

2

完整版本

def shouldShift(char):
    return char in string.lowercase

def caesarShift(string, n):
    def letterToNum(char):
        return ord(char)-ord('a')
    def numToLetter(num):
        return chr(num+ord('a'))

    def shiftByN(char):
        return numToLetter((letterToNum(char)+n) % 26)

    return ''.join((shiftByN(c) if shouldShift(c) else c) for c in string.lower())

一句话概括

如果你真的想要一个一句话概括,那就是这个,但我觉得它比较丑陋:

''.join(chr((ord(c)-ord('a')+n)%26 + ord('a')) for c in string)

演示


>>> caesarShift(string.lowercase, 3)
'defghijklmnopqrstuvwxyzabc'

1

尝试使用列表推导式:

input = 'ABC'
''.join(chr(ord(c)+2) for c in input)
> 'CDE'

这比使用正则表达式更简单。


抱歉向HAL 9000致敬,但这个编程代码''.join(chr(ord(c)+1)for c in 'HAL')也可以实现同样的效果。 - Óscar López

0
def CaesarCipher(s1,num):
new_str = ''
for i in s1:
    asc_V = ord(i)

    if asc_V in range(65, 91):
        if asc_V + num > 90:
            asc_val = 65 + (num - 1 - (90 - asc_V))
        else:
            asc_val = asc_V + num

        new_str = new_str + chr(asc_val)


    elif (asc_V in range(97, 123)):
        if asc_V + num > 122:
            asc_val = 97 + (num - 1 - (122 - asc_V))
        else:
            asc_val = asc_V + num

        new_str = new_str + chr(asc_val)

    else:
        new_str = new_str + i

return new_str        

print (CaesarCipher("HEllo", 4))

打印(CaesarCipher("HEllo", 4))

print (CaesarCipher("xyzderBYTE", 2))

打印(CaesarCipher("xyzderBYTE", 2))


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接