Pythonで文字列の1文字を変更する


385

Pythonで文字列の文字を置き換える最も簡単な方法は何ですか?

例えば:

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

回答:


534

文字列を変更しないでください。

それらをリストとして使用します。必要な場合にのみ文字列に変換します。

>>> 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文字列は不変です(つまり、変更できません)。これには多くの理由があります。選択肢がなくなるまでリストを使用します。リストを文字列に変換してください。


4
速度/効率性をお求めの方は、こちらをお読みください
AneesAhmed777 '19

4
「文字列を変更しないでください。」理由
hacksoi

2
「作成->変更->シリアライズ->割り当て->フリー」は、s [6] = 'W'よりも効率的ですか?うーん...理由がたくさんあるにもかかわらず、なぜ他の言語がそれを許可しているのでしょうか。奇妙なデザインをどのように防御できるか興味深い(愛のために私は推測する)。文字列全体を不必要にバイトシャッフルするのではなく、charメモリ位置に直接アクセスする関数MID(strVar、index、newChar)をPythonコアに追加することを提案しませんか?
オスカー

@ hacksoi、@ oscar、理由は非常に単純です:コピーオンモディファイを実装するためにポインターを渡すときに再カウントする必要はありません、または誰かがその文字列を変更したい場合に備えて文字列全体を完全にコピーします-これは一般的な速度の向上につながります使用する。MIDスライスによるものなどの必要はありません:s[:index] + c + s[index+1:]
MultiSkill

1
@oscarダム言語とは、明示的に指示しない限り、Unicodeを処理しないことを意味します。もちろん、Unicode対応のアプリケーションをCで作成することもできます。ただし、常に気にかける必要があり、問題を回避するために明示的にテストする必要があります。すべてが機械指向です。私はPythonを学ぶ前にPHPを使っていましたが、その言語は完全に混乱しています。高速CPUに関するあなたのメモについて、私は完全にあなたと一緒です。しかし、その問題の一部は、途中で大量のCPUサイクルをリークすることによってインタープリターとライブラリーの速度を低下させる、時期尚早な最適化の一般的な不承認です。
Bachsau

202

最速の方法?

3つの方法があります。スピードを求める人には「方法2」をお勧めします

方法1

この答えによって与えられる

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

「方法2」に比べてかなり遅い

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

方法2(高速方法)

この答えによって与えられる

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

これははるかに高速です:

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

方法3:

バイト配列:

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

1
それがbytearrayメソッドにもどのように対抗するかを見るのも興味深いでしょう。
2015年

1
良い提案。bytearrayメソッドも低速ですtimeit.timeit("text = 'abcdefg'; s = bytearray(text); s[1] = 'Z'; str(s)", number=1000000)。最高速の2倍の速度です。
Mehdi Nellen 2015年

2
テストに感謝します。これにより、Python文字列の操作方法を再考することができます。
スペクトル

1
いいね。回答を編集してメソッド3も含めるようにしてください(bytearray)。
AneesAhmed777 2017

1
ここでのほとんどの時間は変換に費やされていることに注意してください...(文字列->バイト配列)。文字列に加える編集が多い場合は、バイト配列メソッドの方が高速です。
Ian Sudbery 2018年


37

Python文字列は不変です。コピーを作成して変更します。
あなたが望むことをする最も簡単な方法はおそらく:

text = "Z" + text[1:]

text[1:]リターンの文字列text末尾に位置1からは、位置が0から「1」のように、カウント番目の文字です。

編集:文字列のどの部分にも同じ文字列スライス手法を使用できます

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

または、文字が一度だけ表示される場合は、以下で提案されている検索と置換のテクニックを使用できます


2番目の文字であるIEをメンテします。場所番号1の文字(1番目の文字、番号0と
同様

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

13

python 2.6とpython 3以降では、変更可能なバイト配列を使用できます(文字列とは異なり、要素ごとに変更できます)。

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

編集:strをsに変更

edit2:Two-Bit Alchemistがコメントで述べたように、このコードはユニコードでは機能しません。


この答えは間違っています。一つには、それはでbytearray(s)はなく、であるべきbytearray(str)です。別の場合、これは以下を生成しますTypeError: string argument without an encoding。エンコーディングを指定すると、を取得しTypeError: an integer is requiredます。これは、Python 3またはPython 2のユニコードの場合です。これをPython 2で(2行目を修正して)実行すると、ASCII以外の文字は1バイトではない可能性があるため機能しません。でそれを試してみてs = 'Héllo'、あなたが取得します'He\xa9llo'
2ビットの錬金術師、

これをPython 2.7.9でもう一度試しました。あなたが言及したエラーを再生成できませんでした(TypeError:エンコーディングなしの文字列引数)。
Mahmoud

このエラーは、Unicodeを使用している場合にのみ適用されます。お試しくださいs = u'abcdefg'
2ビットの錬金術師

4
こんなことしないで。このメソッドは文字列エンコーディングの概念全体を無視します。つまり、ASCII文字でのみ機能します。この時代では、たとえ英語圏の国で英語を話す人であっても、ASCIIを仮定することはできません。Python3の最大の後方非互換性、そして私の意見では最も重要なことは、このバイト全体=文字列の偽の等価性を修正することです。持ち帰らないでください。
アダム

5

他の人が言ったように、一般にPython文字列は不変であると想定されています。

ただし、python.orgでの実装であるCPythonを使用している場合は、ctypesを使用してメモリ内の文字列構造を変更できます。

これは、文字列をクリアする手法を使用する例です。

Pythonでデータを機密としてマーク

完全を期すためにこれについて触れますが、ハックなので、これが最後の手段になるはずです。


6
最後の手段?あなたがいる場合、これまでこれを行う、あなたは突然悪の烙印を押されています!
Chris Morgan

文字列にパスワードが含まれている場合、@ ChrisMorganは、s = ''を使用してパスワードをクリアしても、パスワードがメモリ内のどこかにまだ書き込まれているため、十分ではありません。ctypesでそれをクリアすることが唯一の方法です。
カブ

1
@Cabu どんな状況で、そのようなコードを受け入れることはありません。データの機密性が高く、このようなセキュリティに関心がある場合は、適切なタイプではありません。使用しないでください。代わりに次のようなものを使用してください。(さらに良いことに、多かれ少なかれ不透明なデータとして扱うことができるようにラップして、本当にそこからを取得できないようにし、事故からあなたを保護します。そのためのライブラリがあるかもしれません。アイデアはありません。)strbytearraystr
クリスモーガン

4

このコードは私のものではありません。私はそれを取った場所のフォームを思い出すことができませんでした。興味深いことに、これを使用して、1つ以上の文字を1つ以上の文字に置き換えることができます。この返信は非常に遅いですが、私のような初心者は(いつでも)役に立つと思うかもしれません。

テキスト機能を変更します。

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

11
これは質問の答えにはなりません。それはまったく望まれていなかった。
Chris Morgan

2
最初のコードのみを置き換えたい場合、このコードは不適切ですlmytext = mytext.replace('l', 'W')->HeWWo Zorld
Ooker

あなたが外科的に1文字(私です)のみを置き換えることを求めている場合、これは請求書に完全に適合します。ありがとう!
ProfVersaggi、2015年

@ProfVersaggiそれは間違いです。上記のOokerのコメントを参照してください。
2ビットの錬金術師

3
@Ooker 最初の文字だけを置き換えたい場合は、を使用できますmytext = mytext.replace('l', 'W',1)ドキュメントへのリンク
Alex

2

実際には、文字列を使用すると、次のようなことができます。

oldStr = 'Hello World!'    
newStr = ''

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

'HELLO WORLD!'

基本的に、私は一緒に新しい文字列に「追加」+「文字列」しています:)。


4
これらは不変であるため、すべての連結が新しい文字列オブジェクトを生成する必要があるため、これは非常に遅くなります。これは、この質問についてです。
2ビットの錬金術師、

0

世界が100%の場合ascii/utf-8(多くのユースケースがそのボックスに収まります):

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

文字列の文字を変更する別の方法を追加したいと思います。

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

文字列をリストに変換し、i番目の値を置き換えてから再度結合する場合と比較すると、どれくらい高速ですか。

リストアプローチ

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

私の解決策

>>> timeit.timeit("text = '~~~~~~~~~~~'; text=text[:1] + (text[1:].replace(text[0], '+', 1))", number=1000000)
0.588400217000526
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.