Python'da bir dizedeki bir karakteri değiştirme


385

Python'da bir dizgideki bir karakteri değiştirmenin en kolay yolu nedir?

Örneğin:

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

Yanıtlar:


534

Dizeleri değiştirmeyin.

Onlarla liste halinde çalışın; bunları yalnızca gerektiğinde dizgilere dönüştürün.

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

Python dizeleri değiştirilemez (yani değiştirilemez). Bunun birçok nedeni var. Başka seçeneğiniz kalmayıncaya kadar listeleri kullanın, ancak bunları dizelere dönüştürün.


4
Hız / verimlilik arayanlar, bunu okuyun
AneesAhmed777

4
"Dizeleri değiştirmeyin." neden
hacksoi

2
"Oluştur-> değiştir-> serialize-> ata-> ücretsiz" s [6] = 'W'den daha mı verimli? Hmm ... Neden bu "sürü" ye rağmen diğer diller buna izin veriyor? Tuhaf bir tasarımın nasıl savunulabileceği ilginç (sanırım aşk için). Python çekirdeğine, tüm dizeyle gereksiz yere bayt karıştırmak yerine, char bellek konumuna doğrudan erişen bir MID (strVar, index, newChar) işlevi eklemeyi neden önermiyorsunuz?
oscar

@hacksoi, @oscar, bunun nedeni oldukça basit: değiştirilen kopyalamayı uygulamak için işaretçilerden geçerken yeniden ifade etmeye gerek yok veya birisi bu dizeyi değiştirmek istemesi durumunda tüm dizeyi açıkça kopyalamaya gerek yok - bu, genel hız artışına yol açar kullanın. MIDDilimler gibi şeylere gerek yoktur :s[:index] + c + s[index+1:]
MultiSkill

1
@oscar Aptal dillerle, açıkça onlara söylemediğiniz sürece unicode ile uğraşmadıklarını kastediyorum. Tabii ki C'de unicode özellikli uygulamalar yazabilirsiniz. Ancak bunu her zaman önemsemelisiniz ve sorundan kaçınmak için açıkça test etmeniz gerekir. Her şey makine odaklı. Python öğrenmeden önce PHP ile çalıştım ve bu dil tam bir karmaşa. Hızlı CPU'lara ilişkin notunuzla ilgili olarak tamamen sizinle birlikteyim. Ancak bu sorunun bir kısmı, erken optimizasyonun popüler olarak reddedilmesidir, bu da yolda çok sayıda CPU döngüsü sızdırarak yavaş tercümanlara ve kütüphanelere yol açar.
Bachsau

202

En hızlı yöntem?

Üç yol var. Hız arayanlar için 'Yöntem 2'yi öneriyorum

Yöntem 1

Bu cevap tarafından verildi

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

Bu, 'Yöntem 2'ye kıyasla oldukça yavaş

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

Yöntem 2 (HIZLI YÖNTEM)

Bu cevap tarafından verildi

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

Hangisi çok daha hızlı:

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

Yöntem 3:

Bayt dizisi:

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

1
Bytearray yöntemine de nasıl geldiğini görmek ilginç olurdu.
gaborous

1
İyi öneri. Bytearray yöntemi de daha yavaştır: timeit.timeit("text = 'abcdefg'; s = bytearray(text); s[1] = 'Z'; str(s)", number=1000000)en hızlı olanın iki katı kadar yavaştır.
Mehdi Nellen

2
Python dizelerini nasıl kullanmam gerektiğini yeniden düşünmemi sağlayan testleri takdir et.
Spectral

1
Güzel. Lütfen yanıtı yöntem 3'ü de içerecek şekilde düzenleyin (bytearray).
AneesAhmed777

1
Burada çoğu zaman dönüşümlerde geçtiği belirtilmelidir ... (string -> byte array). Dizede yapılması gereken birçok düzenleme varsa, bayt dizisi yöntemi daha hızlı olacaktır.
Ian Sudbery


37

Python dizeleri değişmezdir, bir kopya yaparak değiştirebilirsiniz.
İstediğinizi yapmanın en kolay yolu muhtemelen:

text = "Z" + text[1:]

Dizeyi text[1:]döndürürtext uç konum 1, konumlar bu yüzden '1' ikinci karakter 0 ila sayısı.

edit: Dizenin herhangi bir bölümü için aynı dize dilimleme tekniğini kullanabilirsiniz

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

Veya harf yalnızca bir kez görünüyorsa, aşağıda önerilen arama ve değiştirme tekniğini kullanabilirsiniz


İkinci karakterden bahsediyorum, IE. 1 numaralı yerde yer alan karakter (1. karaktere gösterildiği gibi, 0 sayısı)
kostia

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

13

Python 2.6 ve python 3 ile başlayarak değiştirilebilir olan bytearray'leri kullanabilirsiniz (dizelerden farklı olarak element olarak değiştirilebilir):

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

edit: str s olarak değiştirildi

edit2: İki Bit Simyacı yorumlarda belirtildiği gibi, bu kod unicode ile çalışmaz.


Bu cevap yanlış. Bir kere, öyle olmalı bytearray(s), değil bytearray(str). Bir başka açıdan, bu üretecek: TypeError: string argument without an encoding. Bir kodlama belirtirseniz, alırsınız TypeError: an integer is required. Bu Python 3 veya Python 2'nin unicode'u ile. Bunu Python 2'de (düzeltilmiş ikinci bir satırla) yaparsanız, ASCII olmayan karakterler için çalışmaz, çünkü bunlar sadece bir bayt olmayabilir. Deneyin s = 'Héllo've alacaksınız 'He\xa9llo'.
İki Bit Simyacı

Bunu tekrar Python 2.7.9'da denedim. Bahsettiğiniz hatayı yeniden oluşturamadım (bir kodlama olmadan TypeError: string argümanı).
Mahmud

Bu hata yalnızca unicode kullanıyorsanız geçerlidir. Deneyin s = u'abcdefg'.
İki Bit Simyacı

4
BUNU YAPMA. Bu yöntem tüm dize kodlamaları kavramını yok sayar, yani yalnızca ASCII karakterleri üzerinde çalışır. Bu gün ve yaşta, İngilizce konuşulan bir ülkede İngilizce konuşan biri olsanız bile ASCII'yi kabul edemezsiniz. Python3'ün en büyük geriye dönük uyumsuzluğu ve bence en önemlisi, bu bayt = string false denkliğini düzeltmektir. Geri getirme.
Adam

5

Diğer insanların söylediği gibi, genellikle Python dizelerinin değişmez olması gerekiyordu.

Ancak, python.org'daki uygulama olan CPython kullanıyorsanız, bellekteki dize yapısını değiştirmek için ctypes kullanmak mümkündür.

İşte bir dizeyi temizlemek için tekniği kullandığım bir örnek.

Python'da verileri hassas olarak işaretleme

Bütünlük uğruna bundan bahsediyorum ve hackish olduğu için bu son çare olmalı.


6
Son çare mi? Eğer varsa hiç bunu aniden kötülük olarak markalı!
Chris Morgan

@ChrisMorgan dizeniz bir şifre içeriyorsa, s = '' ile temizlemek yeterli değildir çünkü şifre hala bellekte bir yere yazılmıştır. Ctypes yoluyla temizlemek tek yoldur.
Cabu

1
@Cabu ben ederim asla altında herhangi yaptım kodu kabul koşullar. Verileriniz hassassa ve böyle bir güvenliğe önem veriyorsanız str, sizin için doğru tür değildir. Sadece kullanma. bytearrayBunun gibi bir şey kullanın. (Daha da iyisi, size gerçekten o kadar opak bir veri olarak az ya da çok tedavi sağlayan bir şeyin içine sarın edemez bir almak str, ondan kazalara karşı korumak için. O. Hiçbir fikri için bir kütüphane olabilir.)
Chris Morgan

4

Bu kod benim değil. Nerede aldığımı site formunu hatırlayamıyordum. İlginç bir şekilde, bunu bir veya daha fazla karakteri bir veya daha fazla karakterle değiştirmek için kullanabilirsiniz. Bu cevap çok geç olsa da, benim gibi acemiler (her zaman) yararlı bulabilir.

Metin işlevini değiştir.

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

11
Bu soruya cevap vermiyor. Hiç istenen şey değildi.
Chris Morgan

2
Yalnızca ilkini değiştirmek istiyorsanız bu kod kötüdür l. mytext = mytext.replace('l', 'W')->HeWWo Zorld
Ooker

Sadece 1 karakteri (ki ben) cerrahi olarak değiştirmek istiyorsanız, bu tasarıyı mükemmel uyuyor. Teşekkürler!
ProfVersaggi

@ProfVersaggi Bu kesinlikle yanlış. Yukarıdaki Ooker'ın yorumuna bakın.
İki Bit Simyacı

3
@Ooker Yalnızca ilk karakteri değiştirmek isterseniz kullanabilirsiniz mytext = mytext.replace('l', 'W',1).
Alex

2

Aslında, dizelerle böyle bir şey yapabilirsiniz:

oldStr = 'Hello World!'    
newStr = ''

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

'HELLO WORLD!'

Temel olarak, yeni bir dizeye "+" dizeleri "ekliyorum :).


4
Bu çok yavaş olacaktır, çünkü her birleştirme yeni bir dize nesnesi üretmek zorundadır, çünkü değişmezler, bu soru budur.
İki Bit Simyacı

0

dünyanız% 100 ise ascii/utf-8(bu kutuya birçok kullanım durumu sığar):

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

Bir dizede bir karakteri değiştirmenin başka bir yolunu eklemek istiyorum.

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

Dizeyi listeye dönüştürmek ve ith değerini değiştirmek ve tekrar katılmakla karşılaştırıldığında ne kadar hızlı?

Liste yaklaşımı

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

Çözümüm

>>> timeit.timeit("text = '~~~~~~~~~~~'; text=text[:1] + (text[1:].replace(text[0], '+', 1))", number=1000000)
0.588400217000526
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.