2016-11-27 1 views
3

Comment remplacer une chaîne par une autre à l'intérieur d'un StringIO? - J'ai entendu dire que c'est possible s'ils ont la même longueur.remplacement sur place dans StringIO

Tentative:

from cStringIO import StringIO 

c = 'can\nhaz\nfoo' 

sio = StringIO(c) 

for line in sio: 
    if line == 'haz\n': 
     # sio.write('bar\n') 
     line = 'bar\n' 
     break 

sio.seek(0) 
sio.readlines() # [ 'can\n', 'haz\n', 'bar' ] 

PS: Elle travaille actuellement sur une solution en C, mais ferait bien plutôt ce travail.

Répondre

3

StringIO essaie d'imiter un fichier normal en lecture/écriture, sauf qu'il est stocké en mémoire. Vous avez les mêmes problèmes lorsque vous essayez d'éditer un fichier texte sur place qu'avec un fichier normal (le remplacement par une chaîne plus longue écrase la ligne suivante). Vous avez également les mêmes options.

Petit autre changement: cStringIO créé avec une chaîne par défaut au démarrage n'est pas accessible en écriture. Mais vous pouvez contourner cela en créant un objet vide et écrire (vous avez évidemment accès à une méthode write maintenant)

Qu'est-ce que vous cherchez:

c = 'can\nhaz\nfoo' 

sio = StringIO() 
sio.write(c) 
sio.seek(0) 

offset = sio.tell() 
for line in sio: 
    if line == 'haz\n': 
     sio.seek(offset) 
     sio.write('bar\n') 
     break 
    offset = sio.tell() 

Il stocke le décalage avant le lineread et si le modèle est trouvé, il recherche le décalage précédent, et écrit le même nombre d'octets

Solution brutale si vous voulez utiliser cStringIO: vous pouvez lire complètement le tampon, effectuer votre remplacement, et réécrire à lui (permet de remplacer par st plus anneaux), mais lit le tampon entier, ce qui est probablement pas ce que vous voulez:

c = 'can\nhaz\nfoo' 

sio = StringIO(c) 

v = sio.getvalue() 
v = v.replace("haz","bar") 
sio.seek(0) 
sio.write(v) 

Notez que Python 3 retiré ces objets, maintenant il est juste io. Donc, compter sur telle ou telle implémentation rendra votre code non portable.

+0

Merci d'avoir fait le tour, mais un petit changement: 'AttributeError: l'objet 'cStringIO.StringIO' n'a pas d'attribut 'write''; le déplacement vers l'objet 'StringIO.StringIO' normal a résolu ce problème. Mais maintenant, ça ne va pas être beaucoup plus lent? :( –

+0

Désolé je viens de remarquer que la méthode 'write' n'existait pas si la chaîne était déjà peuplée Voir mon edit qui fonctionne aussi avec' cStringIO'. –