Modifica di un carattere in una stringa in Python


385

Qual è il modo più semplice in Python per sostituire un carattere in una stringa?

Per esempio:

text = "abcdefg";
text[1] = "Z";
           ^

Risposte:


535

Non modificare le stringhe.

Lavora con loro come liste; trasformali in stringhe solo quando necessario.

>>> s = list("Hello zorld")
>>> s
['H', 'e', 'l', 'l', 'o', ' ', 'z', 'o', 'r', 'l', 'd']
>>> s[6] = 'W'
>>> s
['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd']
>>> "".join(s)
'Hello World'

Le stringhe di Python sono immutabili (cioè non possono essere modificate). Ci sono molte ragioni per questo. Usa gli elenchi fino a quando non hai scelta, solo successivamente trasformali in stringhe.


4
Chi è alla ricerca di velocità / efficienza, leggi questo
AneesAhmed777,

4
"Non modificare le stringhe." perché
hacksoi,

2
"Crea-> modifica-> serializza-> assegna-> libero" più efficace di s [6] = 'W'? Hmm ... Perché altre lingue lo consentono, nonostante quel "sacco" di ragioni? Interessante come si possa difendere uno strano disegno (suppongo per amore). Perché non suggerire di aggiungere una funzione MID (strVar, index, newChar) al core Python che accede direttamente alla posizione della memoria char, invece di mescolare inutilmente i byte con l'intera stringa?
Oscar

@hacksoi, @oscar, il motivo è abbastanza semplice: non è necessario ricontattare quando si passano i puntatori per implementare copia su modifica o copiare completamente l'intera stringa nel caso in cui qualcuno voglia modificare quella stringa - questo porta ad aumentare la velocità in generico uso. Non c'è bisogno di cose come quelle MIDdovute alle sezioni:s[:index] + c + s[index+1:]
MultiSkill

1
@oscar Con lingue stupide intendo che non hanno a che fare con unicode a meno che tu non glielo dica esplicitamente. Ovviamente puoi scrivere applicazioni compatibili con Unicode in C. Ma devi sempre preoccupartene e devi testarlo esplicitamente per evitare problemi. Tutto è orientato alla macchina. Ho lavorato con PHP prima di imparare Python e quella lingua è un casino totale. Per quanto riguarda la tua nota sulle CPU veloci, sono totalmente con te. Ma una parte di questo problema è la disapprovazione popolare dell'ottimizzazione prematura, che porta a rallentare gli interpreti e le librerie perdendo molti cicli della CPU lungo la strada.
Bachsau,

202

Metodo più veloce?

Ci sono tre modi. Per i cercatori di velocità consiglio 'Metodo 2'

Metodo 1

Dato da questa risposta

text = 'abcdefg'
new = list(text)
new[6] = 'W'
''.join(new)

Che è piuttosto lento rispetto al "Metodo 2"

timeit.timeit("text = 'abcdefg'; s = list(text); s[6] = 'W'; ''.join(s)", number=1000000)
1.0411581993103027

Metodo 2 (METODO VELOCE)

Dato da questa risposta

text = 'abcdefg'
text = text[:1] + 'Z' + text[2:]

Che è molto più veloce:

timeit.timeit("text = 'abcdefg'; text = text[:1] + 'Z' + text[2:]", number=1000000)
0.34651994705200195

Metodo 3:

Matrice di byte:

timeit.timeit("text = 'abcdefg'; s = bytearray(text); s[1] = 'Z'; str(s)", number=1000000)
1.0387420654296875

1
Sarebbe interessante vedere come si comporta anche con il metodo bytearray.
gaboroso

1
Buon consiglio Anche il metodo bytearray è più lento: timeit.timeit("text = 'abcdefg'; s = bytearray(text); s[1] = 'Z'; str(s)", number=1000000)due volte più lento di quello più veloce.
Mehdi Nellen,

2
Apprezzo i test, che mi fanno ripensare a come dovrei manipolare le stringhe di Python.
Spectral,

1
Bello. Modifica la risposta per includere anche il metodo 3 (bytearray).
AneesAhmed777,

1
Va notato che la maggior parte del tempo qui viene impiegato nelle conversioni ... (stringa -> array di byte). Se hai molte modifiche da apportare alla stringa, il metodo array di byte sarà più veloce.
Ian Sudbery,


37

Le stringhe di Python sono immutabili, puoi cambiarle facendo una copia.
Il modo più semplice per fare quello che vuoi è probabilmente:

text = "Z" + text[1:]

Le text[1:]restituisce la stringa nella textdalla posizione 1 alla fine, posizioni contare da 0 così '1' è il secondo carattere.

modifica: è possibile utilizzare la stessa tecnica di suddivisione in stringhe per qualsiasi parte della stringa

text = text[:1] + "Z" + text[2:]

Oppure se la lettera appare solo una volta puoi usare la ricerca e sostituire la tecnica suggerita di seguito


Cito il 2 ° personaggio, IE. il personaggio al posto numero 1 (come allegato al 1o carattere, numero 0)
kostia

testo [0] + "Z" + testo [2:]
wbg

13

A partire da python 2.6 e python 3 è possibile utilizzare i bytearray che sono mutabili (può essere modificato a livello di elemento a differenza delle stringhe):

s = "abcdefg"
b_s = bytearray(s)
b_s[1] = "Z"
s = str(b_s)
print s
aZcdefg

modifica: modificato da str a s

edit2: Come menzionato nei commenti l'alchimista a due bit, questo codice non funziona con Unicode.


Questa risposta non è corretta Per prima cosa, dovrebbe essere bytearray(s), no bytearray(str). Per un altro, questo produrrà: TypeError: string argument without an encoding. Se si specifica una codifica, si ottiene TypeError: an integer is required. Questo è con Unicode di Python 3 o Python 2. Se lo fai in Python 2 (con una seconda riga corretta), non funzionerà con caratteri non ASCII perché potrebbero non essere solo un byte. Provalo con s = 'Héllo'e otterrai 'He\xa9llo'.
Two-Bit Alchemist,

Ho provato di nuovo su Python 2.7.9. Non ho potuto rigenerare l'errore che hai citato (TypeError: argomento stringa senza codifica).
Mahmoud,

Tale errore si applica solo se si utilizza Unicode. Prova s = u'abcdefg'.
Alchimista a due bit,

4
NON FARLO. Questo metodo ignora l'intero concetto di codifiche di stringa, il che significa che funziona solo su caratteri ASCII. Al giorno d'oggi non puoi assumere l'ASCII, anche se sei un madrelingua inglese in un paese di lingua inglese. La più grande incompatibilità all'indietro di Python3, e secondo me la cosa più importante, sta risolvendo l'intero byte = stringa falsa equivalenza. Non riportarlo indietro.
Adam,

5

Come altri hanno già detto, generalmente le stringhe di Python dovrebbero essere immutabili.

Tuttavia, se si utilizza CPython, l'implementazione su python.org, è possibile utilizzare ctypes per modificare la struttura della stringa in memoria.

Ecco un esempio in cui utilizzo la tecnica per cancellare una stringa.

Contrassegna i dati come sensibili in Python

Lo dico per completezza, e questa dovrebbe essere la tua ultima risorsa in quanto è hacker.


6
Ultima risorsa? Se mai lo fai, sei improvvisamente bollato come cattivo!
Chris Morgan,

@ChrisMorgan se la tua stringa contiene una password, cancellarla con s = '' non è sufficiente perché la password è ancora scritta da qualche parte nella memoria. Eliminarlo attraverso i tipi è l'unico modo.
Cabu,

1
@Cabu Non accetterei mai in nessun caso il codice che lo ha fatto. Se i tuoi dati sono sensibili e ti preoccupi della sicurezza in questo modo, strnon è il tipo giusto per te. Basta non usarlo. Usa bytearrayinvece qualcosa di simile . (Meglio ancora, avvolgilo in qualcosa che ti consenta di trattarlo più o meno come un dato opaco in modo da non poterne veramente recuperare uno strda esso, per proteggerti dagli incidenti. Potrebbe esserci una libreria per quello. Nessuna idea.)
Chris Morgan,

4

Questo codice non è mio. Non riuscivo a ricordare il modulo del sito dove l'ho preso. È interessante notare che è possibile utilizzare questo per sostituire uno o più personaggi con uno o più personaggi. Sebbene questa risposta sia molto tardi, i novizi come me (in qualsiasi momento) potrebbero trovarla utile.

Cambia funzione testo.

mytext = 'Hello Zorld'
mytext = mytext.replace('Z', 'W')
print mytext,

11
Questo non risponde alla domanda. Non è affatto quello che si desiderava.
Chris Morgan,

2
Questo codice non è valido se si desidera sostituire solo il primo l. mytext = mytext.replace('l', 'W')->HeWWo Zorld
Ooker

Se stai cercando di sostituire chirurgicamente solo 1 personaggio (che io sono), questo si adatta perfettamente al conto. Grazie!
ProfVersaggi,

@ProfVersaggi Questo è assolutamente falso. Vedi il commento di Ooker sopra.
Two-Bit Alchemist,

3
@Ooker Se vuoi sostituire solo il primo carattere che puoi usare mytext = mytext.replace('l', 'W',1). Link al documento
Alex

2

In realtà, con le stringhe, puoi fare qualcosa del genere:

oldStr = 'Hello World!'    
newStr = ''

for i in oldStr:  
    if 'a' < i < 'z':    
        newStr += chr(ord(i)-32)     
    else:      
        newStr += i
print(newStr)

'HELLO WORLD!'

Fondamentalmente, sto "aggiungendo" + "stringhe" insieme in una nuova stringa :).


4
Questo sarà molto lento perché ogni concatenazione deve produrre un nuovo oggetto stringa, poiché sono immutabili, ed è di questo che tratta questa domanda.
Two-Bit Alchemist,

0

se il tuo mondo è al 100% ascii/utf-8(molti casi d'uso si adattano a quella scatola):

b = bytearray(s, 'utf-8')
# process - e.g., lowercasing: 
#    b[0] = b[i+1] - 32
s = str(b, 'utf-8')

python 3.7.3


0

Vorrei aggiungere un altro modo di cambiare un personaggio in una stringa.

>>> text = '~~~~~~~~~~~'
>>> text = text[:1] + (text[1:].replace(text[0], '+', 1))
'~+~~~~~~~~~'

Quanto è più veloce rispetto alla trasformazione della stringa in elenco e alla sostituzione del valore ith per poi ricollegarsi ?.

Elenco di approccio

>>> timeit.timeit("text = '~~~~~~~~~~~'; s = list(text); s[1] = '+'; ''.join(s)", number=1000000)
0.8268570480013295

La mia soluzione

>>> timeit.timeit("text = '~~~~~~~~~~~'; text=text[:1] + (text[1:].replace(text[0], '+', 1))", number=1000000)
0.588400217000526
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.