在这段代码中,我试图创建一个反元音函数,它将从字符串中删除所有元音(aeiouAEIOU)。我认为它应该可以正常工作,但是当我运行它时,示例文本“嘿,看单词!”作为“Hy lk Words!”返回。它“忘记”删除最后一个“o”。怎么会这样?
text = "Hey look Words!"
def anti_vowel(text):
textlist = list(text)
for char in textlist:
if char.lower() in 'aeiou':
textlist.remove(char)
return "".join(textlist)
print anti_vowel(text)
您正在修改正在迭代的列表,这必然会导致一些不直观的行为。相反,复制列表,这样就不会从迭代的内容中删除元素。
为了澄清你看到的行为,看看这个。把
print char, textlist
放在(原始)循环的开头。您可能会期望,这会在列表旁边垂直打印出字符串,但实际得到的是:怎么了?Python中漂亮的
for x in y
循环实际上只是语法上的糖:它仍然按索引访问列表元素。因此,当您在列表上迭代时从列表中删除元素时,就开始跳过值(如上图所示)。因此,在"look"
中永远看不到第二个o
;您跳过它是因为当您删除前一个元素时,索引已经“超过”了它。然后,当您到达"Words"
中的o
时,您将删除'o'
的第一个匹配项,这是您之前跳过的一个匹配项。正如其他人所提到的,列表理解可能是一种更好(更干净、更清晰)的方法。利用Python字符串是可iterable的这一事实:
引用from the docs:
使用
[:]
遍历列表的浅副本。您在迭代列表时正在修改它,这将导致某些字母丢失。循环
for
跟踪索引,因此当您删除索引i
处的项时,第i+1
位置处的下一项将移到当前索引(i
),因此在下一次迭代中,您将实际选择第i+2
项。举个简单的例子:
迭代1:索引=0。
char = 'W'
在索引0处。因为它不满足那个条件,所以你什么也不做。迭代2:索引=1。
char = 'h'
在索引1处。这里没什么可做的了。迭代3:索引=2。
char = 'o'
在索引2中。由于此项满足条件,因此它将从列表中移除,并且其右侧的所有项将向左移动一个位置以填补空白。现在
textlist
变成:如您所见,另一个
'o'
移动到了索引2,即当前索引,因此在下一次迭代中将跳过它。所以,这就是为什么有些项目在迭代中被跳过的原因。无论何时删除项,都将跳过迭代中的下一项。迭代4:索引=3。
char = 'p'
在索引3处。。。。。
修复:
迭代列表的浅层副本以解决此问题:
其他替代方案:
列表理解:
使用
str.join
和list comprehension
的一行:正则表达式:
其他答案告诉您为什么在更改列表时
for
跳过项。这个答案告诉您应该如何删除字符串中没有显式循环的字符。使用^{} :
这将删除第二个参数中列出的所有字符。
演示:
在Python 3中,
str.translate()
方法(Python 2:unicode.translate()
)的不同之处在于它不接受deletechars参数;第一个参数是将Unicode序号(整数值)映射到新值的字典。对于需要删除的任何字符,请使用None
:您还可以使用^{} static method 生成该映射:
相关问题 更多 >
编程相关推荐