[英]What's the best way to “periodically” replace characters in a string in Python?
I have a string where a character ('@') needs to be replaced by characters from a list of one or more characters "in order" and "periodically". 我有一个字符串,其中一个字符('@')需要被“按顺序”和“定期”的一个或多个字符列表中的字符替换。 So for example I have
所以我举个例子
'ab@cde@@fghi@jk@lmno@@@p@qrs@tuvwxy@z'
and want 并希望
'ab1cde23fghi1jk2lmno312p3qrs1tuvwxy2z'
for replace_chars = ['1', '2', '3']
for
replace_chars = ['1', '2', '3']
The problem is that in this example there are more @ in the string than I have replacers. 问题是在这个例子中,字符串中的@比我有替换者的更多。
This is my try: 这是我的尝试:
result = ''
replace_chars = ['1', '2', '3']
string = 'ab@cde@@fghi@jk@lmno@@@p@qrs@tuvwxy@z'
i = 0
for char in string:
if char == '@':
result += replace_chars[i]
i += 1
else:
result += char
print(result)
but this only works of course if there are not more than three @ in the original string and otherwise I get IndexError . 但是这只有在原始字符串中不超过3个@的情况下才有效,否则我会得到IndexError 。
Edit: Thanks for the answers! 编辑:谢谢你的回答!
Your code could be fixed by adding the line i = i%len(replace_chars)
as the last line of your if
clause. 您的代码可以通过添加行
i = i%len(replace_chars)
作为if
子句的最后一行来修复。 This way you will be taking the remainder from the division of i
by the length of your list of replacement characters. 通过这种方式,您将从
i
的除法中取出剩余的替换字符列表的长度。
The shorter solution is to use a generator that periodically spits out replacement characters. 较短的解决方案是使用定期吐出替换字符的生成器。
>>> from itertools import cycle
>>> s = 'ab@cde@@fghi@jk@lmno@@@p@qrs@tuvwxy@z'
>>> replace_chars = ['1', '2', '3']
>>>
>>> replacer = cycle(replace_chars)
>>> ''.join([next(replacer) if c == '@' else c for c in s])
'ab1cde23fghi1jk2lmno312p3qrs1tuvwxy2z'
For each character c
in your string s
, we get the next replacement character from the replacer
generator if the character is an '@'
, otherwise it just gives you the original character. 对于字符串
s
每个字符c
,如果字符为'@'
,我们将从replacer
生成器中获取下一个替换字符,否则它只会为您提供原始字符。
For an explanation why I used a list comprehension instead of a generator expression, read this . 为了解释为什么我使用列表推导而不是生成器表达式,请阅读此内容 。
Generators are fun. 发电机很有趣。
def gen():
replace_chars = ['1', '2', '3']
while True:
for rc in replace_chars:
yield rc
with gen() as g:
s = 'ab@cde@@fghi@jk@lmno@@@p@qrs@tuvwxy@z'
s = ''.join(next(g) if c == '@' else c for c in s)
As PM 2Ring suggested, this is functionally the same as itertools.cycle
. 正如PM 2Ring所建议的那样,这在功能上与
itertools.cycle
相同。 The difference is that itertools.cycle
will hold an extra copy of the list in memory which may not be necessary. 区别在于
itertools.cycle
将在内存中保存一个额外的列表副本,这可能不是必需的。
itertools.cycle
source: itertools.cycle
源码:
def cycle(iterable):
saved = []
for element in iterable:
yield element
saved.append(element)
while saved:
for element in saved:
yield element
You could also keep your index logic once you use modulo, using a list comp by using itertools.count
to keep track of where you are: 一旦使用模数,您也可以保留索引逻辑,使用列表comp通过使用
itertools.count
来跟踪您的位置:
from itertools import count
cn, ln = count(), len(replace_chars)
print("".join([replace_chars[next(cn) % ln] if c == "@" else c for c in string]))
ab1cde23fghi1jk2lmno312p3qrs1tuvwxy2z
I think it is better to not iterate character-by-character, especially for long string with lengthy parts without @
. 我认为最好不要逐个字符地迭代,特别是对于没有
@
冗长部分的长字符串。
from itertools import cycle, chain
s = 'ab@cde@@fghi@jk@lmno@@@p@qrs@tuvwxy@z'
replace_chars = ['1', '2', '3']
result = ''.join(chain.from_iterable(zip(s.split('@'), cycle(replace_chars))))[:-1]
I don't know how to efficiently kill last char [:-1]
. 我不知道如何有效地杀死最后一个char
[:-1]
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.