Mengubah satu karakter dalam string dengan Python

385

Apa cara termudah dalam Python untuk mengganti karakter dalam string?

Sebagai contoh:

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

Jawaban:

535

Jangan modifikasi string.

Bekerja dengan mereka sebagai daftar; mengubahnya menjadi string hanya saat dibutuhkan.

>>> 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'

String python tidak dapat diubah (artinya tidak dapat dimodifikasi). Ada banyak alasan untuk ini. Gunakan daftar sampai Anda tidak punya pilihan, hanya kemudian mengubahnya menjadi string.

scvalex
sumber
4
Mereka yang mencari kecepatan / efisiensi, baca ini
AneesAhmed777
4
"Jangan memodifikasi string." mengapa
hacksoi
2
"Buat-> modifikasi-> serialize-> assign-> gratis" lebih efisien daripada s [6] = 'W'? Hmm ... Mengapa bahasa lain mengizinkannya, meskipun ada "banyak" alasan? Menarik bagaimana desain yang aneh dapat dipertahankan (untuk cinta kurasa). Mengapa tidak menyarankan menambahkan fungsi MID (strVar, index, newChar) ke inti Python yang secara langsung mengakses posisi memori char, alih-alih byte shuffling dengan seluruh string yang tidak biasa?
oscar
@hacksoi, @oscar, alasannya cukup sederhana: tidak perlu melakukan penghitungan ulang ketika melewati pointer di sekitar untuk menerapkan copy-on-memodifikasi, atau langsung menyalin seluruh string jika seseorang ingin memodifikasi string itu - ini mengarah pada peningkatan kecepatan generik menggunakan. Tidak perlu untuk hal-hal seperti MIDkarena irisan:s[:index] + c + s[index+1:]
MultiSkill
1
@oscar Dengan bahasa bodoh saya maksudkan mereka tidak berurusan dengan unicode kecuali jika Anda secara eksplisit mengatakannya. Tentu saja Anda dapat menulis aplikasi yang mampu unicode dalam C. Tapi Anda harus peduli tentang hal itu sepanjang waktu dan perlu mengujinya secara eksplisit untuk menghindari masalah. Semuanya berorientasi pada mesin. Saya bekerja dengan PHP sebelum belajar Python, dan bahasa itu berantakan total. Mengenai catatan Anda tentang CPU cepat, saya benar-benar bersama Anda. Tetapi bagian dari masalah itu adalah ketidaksetujuan populer dari optimasi prematur, yang mengarah pada penafsiran dan perpustakaan yang lambat dengan membocorkan banyak siklus CPU di jalan.
Bachsau
202

Metode tercepat?

Ada tiga cara. Untuk pencari kecepatan saya sarankan 'Metode 2'

Metode 1

Diberikan oleh jawaban ini

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

Yang cukup lambat dibandingkan dengan 'Metode 2'

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

Metode 2 (METODE CEPAT)

Diberikan oleh jawaban ini

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

Yang jauh lebih cepat:

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

Metode 3:

Array byte:

timeit.timeit("text = 'abcdefg'; s = bytearray(text); s[1] = 'Z'; str(s)", number=1000000)
1.0387420654296875
Mehdi Nellen
sumber
1
Akan menarik untuk melihat bagaimana tarifnya terhadap metode bytearray juga.
Gaborous
1
Saran yang bagus Metode bytearray juga lebih lambat: timeit.timeit("text = 'abcdefg'; s = bytearray(text); s[1] = 'Z'; str(s)", number=1000000)dua kali lebih lambat dari yang tercepat.
Mehdi Nellen
2
Menghargai tes, yang membuat saya memikirkan kembali bagaimana saya harus memanipulasi string Python.
Spectral
1
Bagus. Harap Edit jawaban untuk menyertakan metode 3 juga (bytearray).
AneesAhmed777
1
Perlu dicatat bahwa sebagian besar waktu di sini dihabiskan dalam konversi ... (string -> byte array). Jika Anda memiliki banyak pengeditan untuk dibuat ke string, maka metode byte array akan lebih cepat.
Ian Sudbery
37

String python tidak dapat diubah, Anda mengubahnya dengan membuat salinan.
Cara termudah untuk melakukan apa yang Anda inginkan mungkin:

text = "Z" + text[1:]

The text[1:]return string dalam textdari posisi 1 sampai akhir, posisi menghitung dari 0 sehingga '1' adalah karakter kedua.

sunting: Anda dapat menggunakan teknik mengiris string yang sama untuk setiap bagian dari string

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

Atau jika surat itu hanya muncul setelah Anda dapat menggunakan teknik pencarian dan ganti yang disarankan di bawah ini

Martin Beckett
sumber
Saya ment karakter 2, yaitu IE. karakter di tempat nomor 1 (sebagaimana ditambahkan ke karakter 1, nomor 0)
kostia
text [0] + "Z" + text [2:]
wbg
13

Dimulai dengan python 2.6 dan python 3 Anda dapat menggunakan bytearrays yang bisa berubah-ubah (dapat diubah elemen-bijaksana seperti string):

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

edit: Mengubah str ke s

sunting2: Seperti Alchemist Dua-Bit yang disebutkan dalam komentar, kode ini tidak bekerja dengan unicode.

Mahmoud
sumber
Jawaban ini salah. Untuk satu hal, seharusnya bytearray(s), bukan bytearray(str). Untuk yang lain, ini akan menghasilkan: TypeError: string argument without an encoding. Jika Anda menentukan penyandian, maka Anda mendapatkan TypeError: an integer is required. Itu dengan unicode Python 3 atau Python 2. Jika Anda melakukan ini di Python 2 (dengan baris kedua yang diperbaiki), itu tidak akan berfungsi untuk karakter non-ASCII karena mereka mungkin tidak hanya satu byte. Cobalah s = 'Héllo'dan Anda akan mendapatkannya 'He\xa9llo'.
Alchemist Dua-Bit
Saya mencoba ini lagi di Python 2.7.9. Saya tidak bisa membuat ulang kesalahan yang Anda sebutkan (TypeError: argumen string tanpa pengkodean).
Mahmoud
Kesalahan itu hanya berlaku jika Anda menggunakan unicode. Coba s = u'abcdefg'.
Alchemist Dua-Bit
4
JANGAN LAKUKAN INI. Metode ini mengabaikan seluruh konsep pengkodean string, yang berarti hanya terjadi pada karakter ASCII. Di hari ini dan usia Anda tidak dapat mengasumsikan ASCII, bahkan jika Anda seorang penutur bahasa Inggris di negara berbahasa Inggris. Ketidakcocokan terbelakang terbesar Python3, dan menurut saya yang paling penting, adalah memperbaiki seluruh byte ini = string false equivalency. Jangan membawanya kembali.
Adam
5

Seperti orang lain katakan, umumnya string Python seharusnya tidak berubah.

Namun, jika Anda menggunakan CPython, implementasinya di python.org, dimungkinkan untuk menggunakan ctypes untuk memodifikasi struktur string dalam memori.

Berikut adalah contoh di mana saya menggunakan teknik ini untuk menghapus string.

Tandai data sebagai sensitif dalam python

Saya menyebutkan ini demi kelengkapan, dan ini harus menjadi pilihan terakhir Anda karena peretasan.

Tidak dikenal
sumber
6
Resort terakhir? Jika Anda pernah melakukan ini, Anda tiba-tiba dicap jahat!
Chris Morgan
@ChrisMorgan jika string Anda mengandung kata sandi, menghapusnya dengan s = '' tidak cukup karena kata sandi masih tertulis di suatu tempat di memori. Membersihkannya melalui ctypes adalah satu-satunya cara.
Cabu
1
@ Cabu Saya tidak akan pernah dalam keadaan apa pun menerima kode yang melakukan itu. Jika data Anda sensitif dan Anda peduli dengan keamanan seperti ini, strbukan jenis yang tepat untuk Anda. Hanya saja, jangan menggunakannya. Gunakan sesuatu seperti bytearraysebagai gantinya. (Lebih baik lagi, bungkus dengan sesuatu yang memungkinkan Anda memperlakukannya kurang lebih sebagai data buram sehingga Anda benar - benar tidak dapat mengambilnya str, untuk melindungi Anda dari kecelakaan. Mungkin ada perpustakaan untuk itu. Tidak ada perpustakaan.)
Chris Morgan
4

Kode ini bukan milikku. Saya tidak dapat mengingat bentuk situs di mana, saya membawanya. Menariknya, Anda dapat menggunakan ini untuk mengganti satu karakter atau lebih dengan satu atau lebih karakter. Meskipun balasan ini sangat terlambat, pemula seperti saya (kapan saja) mungkin merasa bermanfaat.

Ubah fungsi Teks.

mytext = 'Hello Zorld'
mytext = mytext.replace('Z', 'W')
print mytext,
K.Vee.Shanker.
sumber
11
Ini tidak menjawab pertanyaan. Bukan itu yang diinginkan sama sekali.
Chris Morgan
2
Kode ini adalah buruk jika Anda ingin mengganti hanya yang pertama l. mytext = mytext.replace('l', 'W')->HeWWo Zorld
Ooker
Jika Anda ingin mengganti secara operasi hanya 1 karakter (yang saya) ini cocok dengan tagihan. Terima kasih!
ProfVersaggi
@ProfVersaggi Itu benar-benar salah. Lihat komentar Ooker di atas.
Alchemist Dua-Bit
3
@Ooker Jika Anda ingin mengganti hanya karakter pertama yang dapat Anda gunakan mytext = mytext.replace('l', 'W',1). Tautan ke doc
Alex
2

Sebenarnya, dengan string, Anda dapat melakukan sesuatu seperti ini:

oldStr = 'Hello World!'    
newStr = ''

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

'HELLO WORLD!'

Pada dasarnya, saya "menambahkan" + "string" menjadi string baru :).

pengguna5587487
sumber
4
Ini akan menjadi sangat lambat karena setiap rangkaian harus menghasilkan objek string baru, karena mereka tidak dapat diubah, yang menjadi tujuan pertanyaan ini.
Alchemist Dua-Bit
0

jika dunia Anda 100% ascii/utf-8(banyak kasus penggunaan cocok di dalam kotak itu):

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

python 3.7.3

Paul Nathan
sumber
0

Saya ingin menambahkan cara lain untuk mengubah karakter dalam sebuah string.

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

Seberapa cepat jika dibandingkan dengan mengubah string menjadi daftar dan mengganti nilai h lalu bergabung kembali ?.

Mendaftar pendekatan

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

Solusi saya

>>> timeit.timeit("text = '~~~~~~~~~~~'; text=text[:1] + (text[1:].replace(text[0], '+', 1))", number=1000000)
0.588400217000526
mohammed wazeem
sumber