2010-08-11 5 views
16

En Python, les chaînes sont immuables.Modifications de chaîne «in-situ» en Python

Quelle est l'idiome standard pour parcourir une chaîne caractère par caractère et la modifier?

Les seules méthodes que je peux penser sont des hacks vraiment stanky liés à la réunion contre une chaîne de résultats.

-

En C:

for(int i = 0; i < strlen(s); i++) 
{ 
    s[i] = F(s[i]); 
} 

C'est super expressif et dit exactement ce que je fais. C'est ce que je cherche.

+0

Je suppose, car ils sont immuables, vous ne pouvez pas « la modifier "... voulez-vous dire construire une nouvelle chaîne char-by-char? –

+0

C'est vraiment rare. Pouvez-vous donner un contexte ou un cas d'utilisation pour ce faire? –

+0

Ajouter du bruit à un message pour le tester. –

Répondre

1

Les chaînes sont itérables et peuvent être parcourues dans des listes similaires. Les chaînes ont également un certain nombre de méthodes de base telles que .replace() qui pourrait être ce que vous cherchez. Toutes les méthodes de chaîne renvoient une nouvelle chaîne. Ainsi, au lieu de modifier la chaîne en place, vous pouvez simplement remplacer sa valeur existante.

>>> mystring = 'robot drama' 
>>> mystring = mystring.replace('r', 'g') 
>>> mystring 
'gobot dgama' 
+0

Les chaînes sont * immuables * et ne peuvent pas être attribuées par un membre. –

+0

Correct. Toutes les opérations de chaîne renvoient une copie de la chaîne d'entrée. Cependant, le nom de la variable n'est PAS immuable, donc en ré-affectant une opération de chaîne au même nom de variable, vous "mutez" effectivement la chaîne. – jathanism

+0

"Dans le cas d'altérations à un stging, qui n'augmente pas sa longueur, il serait toujours utile si l'on pouvait utiliser la notation de tranche brouillages ajustements en place:' myStr [0: 3] [:] = 'new'' ".replace (" g "," r ") – CoDEmanX

1
>>> mystring = "Th1s 1s my str1ng" 
>>> mystring.replace("1", "i") 
'This is my string' 

Si vous souhaitez stocker cette nouvelle chaîne vous devrez mystring = mystring.replace("1", "i"). C'est parce que dans les chaînes Python sont immuables.

+0

1: N'utilisez pas" string "comme nom de variable. 2: Cela ne modifie pas la variable. – bstpierre

+0

Cela ne sélectionne pas par index et ne le modifie pas. –

+0

@bstpierre: Voilà. :) –

1

string.translate est probablement la fonction la plus proche de ce que vous recherchez.

+0

Fonction intéressante - ce que je recherche, cependant, c'est de pouvoir ajuster à un index donné (ou retourner une chaîne qui a cet index donné modifié). –

+0

pas besoin d'importer de la chaîne, les objets 'str' ont la méthode' translate'. Il est généralement pratique d'utiliser 'maketrans' du module' string' si –

15

Ne pas utiliser une chaîne, utilisez quelque chose comme mutable bytearray:

#!/usr/bin/python 

s = bytearray("my dog has fleas") 
for n in xrange(len(s)): 
    s[n] = chr(s[n]).upper() 
print s 

Résultats dans:

MY DOG HAS FLEAS 

Edit:

Depuis c'est un bytearray, vous n'êtes pas (nécessairement) travailler avec caractères. Vous travaillez avec octets. Donc, cela fonctionne aussi:

s = bytearray("\x81\x82\x83") 
for n in xrange(len(s)): 
    s[n] = s[n] + 1 
print repr(s) 

donne:

bytearray(b'\x82\x83\x84') 

Si vous souhaitez modifier les caractères dans une chaîne Unicode, vous voudriez peut-être travailler avec memoryview, mais cela ne prend pas en charge Unicode directement .

+2

Ce ne sont pas des caractères, mais seulement des octets. Fonctionne uniquement pour ASCII, pas Unicode. –

+2

Fonctionne pour * octets * valides, pas seulement ASCII. – bstpierre

0
def modifyIdx(s, idx, newchar): 
    return s[:idx] + newchar + s[idx+1:] 
2

L'attribution d'un caractère particulier à un indice particulier dans une chaîne n'est pas une opération particulièrement courante, donc si vous vous trouvez avoir besoin de le faire, pensez à savoir s'il peut y avoir une meilleure façon d'accomplir la tâche. Mais si vous en avez besoin, la méthode la plus courante consiste probablement à convertir la chaîne en liste, à apporter vos modifications et à la convertir en chaîne.

s = 'abcdefgh' 
l = list(s) 
l[3] = 'r' 
s2 = ''.join(l) 

EDIT: Comme écrit dans la réponse de bstpierre, bytearray est sans doute encore mieux pour cette tâche que list, tant que vous ne travaillez pas avec des chaînes Unicode.

s = 'abcdefgh' 
b = bytearray(s) 
b[3] = 'r' 
s2 = str(b) 
+1

Et si vous travaillez avec des chaînes multi-octets, faites attention de ne pas couper un caractère encodé! –

0

Si jamais je dois faire quelque chose comme ça, je convertir simplement à une liste mutable

Par exemple ... (bien qu'il serait plus facile d'utiliser tri (voir le deuxième exemple))

>>> s = "abcdfe" 
>>> s = list(s) 
>>> s[4] = "e" 
>>> s[5] = "f" 
>>> s = ''.join(s) 
>>> print s 
abcdef 
>>> 
# second example 
>>> s.sort() 
>>> s = ''.join(s) 
9

vous pouvez utiliser le module UserString:

>>> import UserString 
... s = UserString.MutableString('Python') 
... print s 
Python 
>>> s[0] = 'c' 
>>> print s 
cython 
+5

Notez que MutableString a été déprécié dans Python 2.6 et supprimé dans Python 3 - https://docs.python.org/2/library/userdict.html#UserString.MutableString – msanders

1

Voici un exemple d'utilisation se traduit pour changer "-" avec "" majuscule « un » s

>>> from string import maketrans 
>>> trans_table = maketrans(".-a","-.A") 
>>> "foo-bar.".translate(trans_table) 
'foo.bAr-' 

Cela est beaucoup plus efficace que le retournement de tableau d'octets et en arrière si vous avez juste besoin de faire remplacer un seul char

15

L'analogue Python de votre C:

for(int i = 0; i < strlen(s); i++) 
{ 
    s[i] = F(s[i]); 
} 

serait:

s = "".join(F(c) for c in s) 

qui est aussi très expressif. Il dit exactement ce qui se passe, mais dans un style fonctionnel plutôt que d'un style procédural.

+0

Intéressant; Je suis un peu comme ça, sauf pour la chaîne nulle. Probablement aussi bon que je vais bien. –

+1

Une partie importante du C pour moi est qu'il fonctionne sur place. –

+1

@Joe Koberg: Une partie importante du Python est qu'il est plus court et plus clair. "en place" est limitant car vous ne pouvez pas allonger la chaîne. –

7

Je dirais que la façon la plus Pythonic est d'utiliser map():

s = map(func, s) # func has been applied to every character in s 

Ceci est l'équivalent de l'écriture:

s = "".join(func(c) for c in s) 
+3

Correction/point mineur: Il faut toujours rejoindre la liste renvoyée (/ iter/map-obj dans Py3 +). Donc, ce qui précède devrait être: 's =" ".join (map (func, s))' – pythonlarry