2016-03-07 2 views
8

Ich habe eine Zeichenfolge, bei der ein Zeichen ('@') durch Zeichen aus einer Liste von einem oder mehreren Zeichen "in der Reihenfolge" und "periodisch" ersetzt werden muss. So zum Beispiel habe ichWas ist der beste Weg, um Zeichen in einer Zeichenfolge in Python "regelmäßig" zu ersetzen?

'[email protected]@@[email protected]@[email protected]@@[email protected]@[email protected]'

und wollen

'ab1cde23fghi1jk2lmno312p3qrs1tuvwxy2z'

für replace_chars = ['1', '2', '3']

Das Problem ist, dass es in diesem Beispiel mehr @ in der Zeichenfolge sind als ich Ersatzgeräte.

Dies ist mein Versuch:

result = '' 
replace_chars = ['1', '2', '3'] 
string = '[email protected]@@[email protected]@[email protected]@@[email protected]@[email protected]' 

i = 0 
for char in string: 
    if char == '@': 
     result += replace_chars[i] 
     i += 1 
    else: 
     result += char 

print(result) 

aber dies funktioniert nur natürlich, wenn es nicht mehr als drei @ in der ursprünglichen Zeichenfolge und sonst bekomme ich Indexerror.

Edit: Danke für die Antworten!

+2

Verwenden Sie 'replace_chars [i% replace_chars.length]'. dann machst du nur bis zu "modulo" der Länge im Index. z.B. mit 3 Zeichen, du machst '1% 3 -> 1',' 2% 3 -> 2', '3% 3 -> 0',' 4% 3 -> 1', etc ... –

+4

Add 'i % = 3' unter 'i + = 1' –

Antwort

10

Ihr Code könnte behoben werden, indem Sie die Zeile i = i%len(replace_chars) als letzte Zeile Ihrer if-Klausel hinzufügen. Auf diese Weise nehmen Sie den Rest aus der Abteilung i um die Länge Ihrer Ersatzzeichenliste.

Die kürzere Lösung besteht darin, einen Generator zu verwenden, der Ersatzzeichen periodisch ausspuckt.

>>> from itertools import cycle 
>>> s = '[email protected]@@[email protected]@[email protected]@@[email protected]@[email protected]' 
>>> replace_chars = ['1', '2', '3'] 
>>> 
>>> replacer = cycle(replace_chars) 
>>> ''.join([next(replacer) if c == '@' else c for c in s]) 
'ab1cde23fghi1jk2lmno312p3qrs1tuvwxy2z' 

Für jedes Zeichen c in Ihrem String s, bekommen wir die nächsten Ersetzungszeichen vom replacer Generator, wenn der Charakter ein '@' ist, sonst gibt es Ihnen nur um den ursprünglichen Charakter.

Für eine Erklärung, warum ich ein Listenverständnis anstelle eines Generatorausdrucks verwendet habe, lesen Sie this.

6

Generatoren machen Spaß.

def gen(): 
    replace_chars = ['1', '2', '3'] 
    while True: 
     for rc in replace_chars: 
      yield rc 

with gen() as g: 
    s = '[email protected]@@[email protected]@[email protected]@@[email protected]@[email protected]' 
    s = ''.join(next(g) if c == '@' else c for c in s) 

Wie PM 2Ring vorgeschlagen, das ist funktional gleich wie itertools.cycle. Der Unterschied besteht darin, dass itertools.cycle eine zusätzliche Kopie der Liste im Speicher enthält, die möglicherweise nicht notwendig ist.

itertools.cycle Quelle:

def cycle(iterable): 
    saved = [] 
    for element in iterable: 
     yield element 
     saved.append(element) 
    while saved: 
     for element in saved: 
       yield element 
+2

Ihr' gen' ist im Wesentlichen was 'itertools.cycle' tut. –

+1

Rechts. In der Regel, selbst wenn es ein nützliches Werkzeug in einem Standardpaket gibt, schreibe ich das native Äquivalent einfach aus Gründen der Lesbarkeit. Die Annahme, man kennt das oben genannte Werkzeug nicht. Oft gibt es nur ein besseres Verständnis. Wenn Sie 'itertools.cycle' verwenden möchten, tun Sie es auf jeden Fall. – Goodies

+0

@ PM2Ring "cycle" speichert auch die Elemente aus dem angegebenen iterable, weil das iterable ein Iterator sein kann, der erschöpft sein kann - aber wenn 'replace_chars' garantiert eine Liste ist, sollte der @Goodies-Generator funktionieren. – timgeb

1

Sie auch Ihre Index Logik halten könnte, wenn Sie Modulo verwenden, unter Verwendung itertools.count eine Liste comp mit, um zu verfolgen, wo Sie sind:

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