Pythonのstr.replaceは、文字列中の特定の部分文字列を別の文字列に置き換える基本かつ強力なメソッドです。
本記事では構文、回数指定、改行やタブの扱い、大文字小文字の違い、そして実務で役立つ注意点とベストプラクティスを、初心者の方にもわかりやすい順序で丁寧に解説します。
str.replaceの基本(初心者向け)
replaceの構文と返り値
replaceは元の文字列を変更せず、新しい文字列を返します。
つまりstrはイミュータブルです。
下の表は構文の各引数の意味をまとめたものです。
| 項目 | 内容 |
|---|---|
| 構文 | new_s = s.replace(old, new, count) |
| s | 置換対象の元文字列 |
| old | 置換したい部分文字列 |
| new | 置換後の文字列 |
| count | 先頭から置換する回数(省略時は全て、0なら何も置換しない) |
| 返り値 | 置換結果の新しい文字列 |
返り値の基本例
# 基本の使い方と返り値の確認
s = "hello world"
t = s.replace("world", "Python")
print("元:", repr(s)) # reprで改行や空白を可視化
print("新:", repr(t))
print("同一オブジェクトか:", s is t) # 新しいオブジェクトが返る
元: 'hello world'
新: 'hello Python'
同一オブジェクトか: False
- 関連記事:比較で使うisと==の違い
文字列をすべて置換する例
countを省略すると全ての一致が置換されます。
# 文字列内の全ての一致を置換
text = "banana bandana banana"
replaced = text.replace("ana", "ANA")
print(repr(replaced))
'banANA bANDAna banANA'
改行(\n)やタブ(\t)を置換する
制御文字も通常の文字と同じように置換できます。
ログ整形やCSV整形でよく使います。
# 改行とタブをスペースに置換して1行に整形する
data = "a\tb\tc\nd\te\tf"
one_line = data.replace("\n", " ").replace("\t", " ")
print("整形前:", repr(data))
print("整形後:", repr(one_line))
整形前: 'a\tb\tc\nd\te\tf'
整形後: 'a b c d e f'
- 関連記事:print()で改行しない方法
元の文字列は変更されない(イミュータブル)
replaceは元のstrを変更しません。
代入を忘れると期待通りに動かないため注意が必要です。
# 代入しないと元の文字列は変わらない
s = "foo bar foo"
s.replace("foo", "baz") # 返り値を捨てている
print(repr(s)) # sはそのまま
'foo bar foo'
- 関連記事:文字列と数値の型を変換したい
- 関連記事:文字列の長さを調べる
回数を指定して置換(count)
count引数の意味と使い方
countは先頭から何回置換するかを指定します。
省略時は全て、0なら何も置換しません。
負数を渡した場合も実質的に全て置換されます。
text = "xx-xx-xx-xx"
print(text.replace("xx", "YY", 1)) # 1回だけ
print(text.replace("xx", "YY", 3)) # 3回だけ
print(text.replace("xx", "YY", 0)) # 0回(置換なし)
YY-xx-xx-xx
YY-YY-YY-xx
xx-xx-xx-xx
先頭からn回だけ置換する例
置換は左から右へ順番に行われます。
先頭寄りの一致から数えてcount回だけ置換されます。
s = "apple, apple, apple, apple"
once = s.replace("apple", "APPLE", 1)
twice = s.replace("apple", "APPLE", 2)
print(once)
print(twice)
APPLE, apple, apple, apple
APPLE, APPLE, apple, apple
一致の重なりは置換されない
Pythonのreplaceは重なり合う一致を数えません。
スライドしながら次の非重複一致を探します。
# "aa" の一致は [0:2], [2:4] の2つ。重複する [1:3] はカウントされない
s = "aaaa"
print(s.replace("aa", "X")) # 2回の非重複一致が "X" に
XX
別例
s = "ababa"
# "aba" は [0:3] と [2:5] で重なる。replaceは先頭の1回だけ一致として扱う
print(s.replace("aba", "X"))
Xba
大文字小文字の扱い(ケースセンシティブ)
replaceは大文字小文字を区別する
replaceはケースセンシティブです。
完全一致しないと置換されません。
s = "Apple apple APPLE"
print(s.replace("apple", "fruit")) # 小文字 "apple" にだけ反応
Apple fruit APPLE
大文字小文字を無視して置換する基本方針
標準のreplaceだけで完全なケース無視置換は困難です。
代表的な方針は次のいずれかです。
- 事前に大小変換して検索位置を決め、該当箇所を組み立て直す
- 正規表現
re.subのre.IGNORECASEを使う(最も簡単)
正規表現を使う例:
import re
s = "Apple apple APPLE"
result = re.sub(r"apple", "fruit", s, flags=re.IGNORECASE)
print(result)
fruit fruit fruit
- 関連記事:正規表現(re)入門
lowerを使った前処理と注意点
lowerで前処理してreplaceすると元の大文字小文字の情報が失われる点に注意します。
置換語の表記を統一したいだけなら有効ですが、元の大文字小文字を保持した置換はできません。
s = "Apple apple APPLE"
# 小文字化したコピーに対して置換し、その結果を使う
t = s.lower().replace("apple", "fruit")
print(t) # 元と同じ長さだが、元の大文字小文字は復元できない
fruit fruit fruit
元の表記を保ちつつ置換したい場合は、前節のre.subと関数置換でケースを調整するのが実務的です。
複数表記をまとめて置換する手順
複数の表記揺れを辞書でまとめて順にreplaceすると管理しやすくなります。
副作用を避けるため、より長いキーから置換するのがコツです(短いキーが長いキーの一部を壊さないようにするため)。
# 表記揺れの正規化
text = "E-mail and email and eMail"
mapping = {
"eMail": "email",
"E-mail": "email",
"email": "email",
}
# 長いキーから置換して副作用を抑える
for old in sorted(mapping.keys(), key=len, reverse=True):
text = text.replace(old, mapping[old])
print(text)
email and email and email
置換の注意点とベストプラクティス
連続置換の順序と副作用
置換の順序により結果が大きく変わることがあります。
特に、置換後の文字列が別の置換の対象と重なる場合、意図せぬ連鎖が起きます。
s = "cat category concatenate"
# 順序A
a = s.replace("cat", "dog").replace("dog", "wolf")
# 順序B
b = s.replace("dog", "wolf").replace("cat", "dog")
print("順序A:", a)
print("順序B:", b)
順序A: wolf wolfegory condogenawolf
順序B: dog dogegory condogenadog
副作用を避けたい場合は以下の工夫が役立ちます。
- ダミーの一時トークンで避難し、最後に戻す
- より長い一致から先に置換する
- そもそも連鎖しない表現を採用する
ダミーを使う最小例:
s = "cat catalog"
tmp_token = "__CAT__"
out = s.replace("cat", tmp_token) \
.replace("dog", "wolf") \
.replace(tmp_token, "dog") # 最後に戻す
print(out)
dog dogalog
補足: oldに空文字""を渡すと各文字の隙間すべてに挿入され、データ量が急増します。
意図しない場合は避けましょう。
print("abc".replace("", "-")) # 各位置に "-" が挿入される
- a - b - c -
単語単位で置換したい場合
replaceは単語境界の概念を持ちません。
単語だけを置換したい場合、空白で分割してから一致したトークンのみ置換するか、単語境界を使った正規表現を検討します。
# 簡易トークン置換(空白区切りの例)
text = "cat scatter category cat"
tokens = text.split() # 本格的には正規表現の分割が望ましい
tokens = ["dog" if t == "cat" else t for t in tokens]
print(" ".join(tokens))
dog scatter category dog
より厳密に単語境界を扱うならre.sub(r"\bcat\b", "dog", text)のような正規表現が向いています。
大きな文字列でのパフォーマンスのコツ
長文や大量データでは、置換回数と文字列の再生成回数を減らすことが重要です。
- 同じ文字列に対する
replaceの多段適用は必要最小限にし、まとめて1回で済む設計にする - 反復処理の内側で毎回
replaceを呼ばず、外側でまとめて呼ぶ - 単文字の大量置換は
str.translateが高速な場合がある(用途が合うとき)
内側での再生成を避ける例:
# 悪い例: ループ内で何度もreplace
lines = ["name:Alice", "name:Bob", "name:Carol"]
bad = [line.replace("name:", "n:").replace("Alice", "A") for line in lines]
print(bad)
# 良い例: まず結合してから一括置換し、必要なら分割に戻す
joined = "\n".join(lines)
joined = joined.replace("name:", "n:").replace("Alice", "A")
good = joined.split("\n")
print(good)
['n:Alice', 'n:Bob', 'n:Carol']
['n:A', 'n:Bob', 'n:Carol']
状況によってはメモリと速度のトレードオフがあるため、timeitで実測するのが最も確実です。
代入忘れに注意(strは不変)
冒頭でも触れた通り、strは不変です。
s.replace(...)の結果を必ず代入してください。
s = "path/to/file"
s.replace("/", "_") # 代入しないと捨てられる
print(s) # 元のまま
s = s.replace("/", "_")
print(s) # 置換済み
path/to/file
path_to_file
まとめ
本記事ではPythonのstr.replaceによる文字列置換の基礎から、回数指定、改行やタブの扱い、ケースセンシティブの特性、そして安全に効率よく置換するための実務的な注意点を解説しました。
重要なのはstrが不変であることを意識し、置換の順序や副作用、表記揺れや大文字小文字の扱いを設計段階で整理することです。
必要に応じてre.subやtranslateなどの手段も検討しつつ、まずはreplaceを正しく使いこなして、読みやすく堅牢な文字列処理を書いていきましょう。
- 関連記事:str.translateで複数文字を一括置換する
- 関連記事:count()で文字列内の特定の文字数を数える
- 関連記事:正規表現(re)入門
