Python:在字符串变化时循环遍历字符

0 投票
2 回答
4938 浏览
提问于 2025-04-18 14:57
def substitutionEncrypt1(text,key):
    plaintext=text.lower()
    alphabet="abcdefghijklmnopqrstuvwxyz "
    for ch in plaintext:
        r=plaintext.index(ch)
        plaintext=plaintext.replace(ch,key[r])
    return plaintext

我的文本是 "The Quick Brown Fox"。 我明白为什么它没有正确加密替换密码,但为什么在第五行时,Python会报错说“没有找到子字符串”? 我不是在遍历明文中的字符吗? 我使用的语言是Python。

谢谢!

2 个回答

2

你的代码有几个问题,导致它根本无法达到你想要的效果。

1. 字符串在Python中是不可变的

在Python中,你不能改变一个字符串。一旦创建了字符串,它就保持不变。你能做的只是基于原来的字符串创建一个新的字符串,并把它赋值给同一个名字。

比如,你可以通过切片的方式来修改一个list(可变类型),在某个位置添加一个新元素:

>>> lst = ['one', 'two', 'three']
>>> lst[0] = 42
>>> lst
[42, 'two', 'three']

但是你不能这样做字符串,因为它们是不可变的:

>>> s = 'abc'
>>> s[1] = 42
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment

所以,你能做的就是给s赋值一个全新的字符串:

>>> s = s.upper()
>>> s
'ABC'

因此,像upper()replace()以及其他字符串方法,都不会直接在原字符串上修改,而是返回一个修改后的新字符串。

至于为什么字符串是不可变的,可以参考这个链接:为什么Python字符串是不可变的?。简单来说,这主要是为了提高性能。


2. 你的循环并没有遍历s,而是遍历了循环开始时s的值

当你写for item in iterable时,Python会这样做:

  • 它获取一个指向循环开始时iterable指向的值的引用。
    • 如果这个值是字符串,它会获取对那个确切字符串的引用。由于字符串是不可变的,这个引用始终指向内存中的同一个对象。
    • 如果这个值是可变的(比如列表),引用会指向那个值。
  • 每次循环时,它会从引用指向的可迭代对象中获取下一个项目。如果这个值是可变的,并且在此期间发生了变化,那就糟糕了,你会得到奇怪的结果。

3. 在遍历可变序列时不应该修改它们

即使str是可变类型,并且你可以修改它,你也不应该在遍历时修改可迭代对象。

举个例子:

lst = [1, 2, 3, 4, 5]

for item in lst:
    print item,
    lst.remove(item)

输出:

1 3 5

如你所见,由于在遍历过程中列表的大小和项目的索引发生了变化,某些项目被跳过了。

对于字典,Python甚至会明确警告你,并中断执行:

dct = dict(foo=23, bar=42)

for key in dct:
    print key
    dct['baz'] = 'qux'

输出:

foo
Traceback (most recent call last):
  File "it.py", line 3, in <module>
    for key in dct:
RuntimeError: dictionary changed size during iteration

所以,考虑到这些,如果你想按照你原本的意图来实现代码,你需要将两个变量分开,一个用于遍历,另一个用于存放转换后的结果。

但因为Python已经有一个translate()函数(正如@Óscar López的回答中解释的那样)专门用于这个目的,所以你应该使用这个函数。

0

你不应该在遍历某个东西的时候(无论是列表、集合还是字典……你懂的)同时对它进行修改。此外,字符串是不可变的,这意味着在每次遍历时,你实际上是在创建新的字符串。要在Python中实现替换密码,没有比使用 translate() 更简单的了——而且我们可以让翻译在两个方向上都能工作:

import string

alphabet = 'abcdefghijklmnopqrstuvwxyz '
subst    = 'edbjvushlpknyxt foqiwacrzgm'

table = string.maketrans(alphabet, subst)
'hello world'.translate(table)
=> 'hvnntmctonj'

table = string.maketrans(subst, alphabet)
'hvnntmctonj'.translate(table)
=> 'hello world'

撰写回答