与えられた文字列の中で、ある部分文字列の全てまたはn回分を置き換えることは、文字列操作やテキスト処理全般においてかなりよくある問題です。幸いなことに、Pythonには膨大な数の組み込み関数があるので、このような作業の大半は簡単に行えます。
例えば、次のような文章を含む文字列があるとします。
The brown-eyed man drives a brown car.
私たちの目標は、"brown"
という単語を"blue"
という単語に置き換えることです。
The blue-eyed man drives a blue car.
この記事では、文字列から部分文字列の出現箇所をすべて置き換えるために、パターン付きの replace()
関数と sub()
関数、 subn()
関数を使用する方法を説明します。
replace()
これを行う最も簡単な方法は、組み込み関数である replace()
を使用することです。
string.replace(oldStr, newStr, count)
最初の2つのパラメータは必須で、3つ目のパラメータはオプションである。oldStr
は newStr
に置き換えたい部分文字列です。注目すべきは、この関数が、元の文字列に影響を与えることなく、変換後の新しい文字列を返すことです。
試してみましょう。
string_a = "The brown-eyed man drives a brown car."
string_b = string_a.replace("brown", "blue")
print(string_a)
print(string_b)
文字列_aに対して処理を行い、その結果を文字列_b
にパックして、両方を表示しました。
このコードの結果は
The brown-eyed man drives a brown car.
The blue-eyed man drives a blue car.
ここでも、string_a
が指しているメモリ上の文字列は変更されていません。Pythonの文字列は不変であり、文字列を変更することはできません。しかし、参照変数に新しい値を再代入することはできます。
この操作をインプレースで行っているように見せるには、操作の後に string_a
を自分自身に再代入すればよいのです。
string_a = string_a.replace("brown", "blue")
print(string_a)
ここでは、 replace()
メソッドによって生成された新しい文字列が string_a
変数に代入されています。
サブストリングのn回目の出現を置き換える
では、部分文字列の出現回数をすべて変更したくない場合はどうすればよいのでしょうか。最初のn個を置き換えたい場合はどうすればいいでしょうか?
そこで登場するのが replace()
関数の第3パラメータです。これは、置換される文字列の数を表します。次のコードでは、最初に現れる単語 "brown"
を "blue"
に置き換えるだけです。
string_a = "The brown-eyed man drives a brown car."
string_a = string_a.replace("brown", "blue", 1)
print(string_a)
そして、これは印刷されます。
The blue-eyed man drives a brown car.
デフォルトでは、3番目のパラメータは、すべての出現箇所を変更するように設定されています。
正規表現を使ったサブストリングの出現頻度
さらに問題をエスカレートさせるために、ある部分文字列の出現箇所をすべて置き換えるだけでなく、あるパターンに合致する部分文字列もすべて置き換えたいとします。このような場合でも、正規表現と標準ライブラリの re
モジュールを使用すれば、ワンライナーで実行することができます。
正規表現はコンピュータサイエンスで幅広く使われる複雑なトピックなので、この記事ではあまり深入りしませんが、もし手っ取り早く始めたいなら、Pythonの正規表現に関するガイドをチェックしてみてください。
本質的には、正規表現はパターンを定義します。例えば、猫と犬を飼っている人についての文章があり、両方の言葉を"pet"
という言葉に変えたい場合を考えてみましょう。まず、(cat|dog)
のように両方の用語にマッチするパターンを定義する必要があります。
sub()関数の使い方
パターンが整理できたので、次の構文の re.sub()
関数を使ってみましょう。
re.sub(pattern, repl, string, count, flags)
最初の引数は検索するパターン (文字列または Pattern
オブジェクト)、repl
は挿入するもの (文字列または関数。文字列の場合、バックスラッシュエスケープは処理されます)、string
は検索対象の文字列です。
オプションの引数は count
と flags
で、それぞれ置換が必要な回数と、正規表現の処理に使用するフラグを指定することができる。
パターンがどの部分文字列にもマッチしない場合、元の文字列は変更されずに返される。
import re
string_a = re.sub(r'(cat|dog)', 'pet', "Mark owns a dog and Mary owns a cat.")
print(string_a)
このコードは次のように表示される。
Mark owns a pet and Mary owns a pet.
大文字・小文字を区別しないパターンマッチング
大文字小文字を区別しないパターンマッチングを行うには、例えば、フラグパラメータに re.IGNORECASE
を設定することになります。
import re
string_a = re.sub(r'(cats|dogs)', "Pets", "DoGs are a man's best friend", flags=re.IGNORECASE)
print(string_a)
これで、"dogs"
の大文字と小文字の組み合わせも含まれるようになります。複数の文字列に対してパターンをマッチングする場合、複数の場所にパターンをコピーするのを避けるために、 Pattern
オブジェクトを定義することができる。また、構文として sub()
関数を持っています。
Pattern.sub(repl, string, count)
パターンオブジェクトの使用
猫と犬のパターンオブジェクトを定義して、いくつかの文章をチェックしてみましょう。
import re
pattern = re.compile(r'(Cats|Dogs)')
string_a = pattern.sub("Pets", "Dogs are a man's best friend.")
string_b = pattern.sub("Animals", "Cats enjoy sleeping.")
print(string_a)
print(string_b)
という出力が得られる。
Pets are a man's best friend.
Animals enjoy sleeping.
subn()関数
構文を持つ subn()
メソッドも存在します。
re.subn(pattern, repl, string, count, flags)
subn()`関数は、検索したStringにマッチした文字列とその数をタプルで返します。
import re
string_a = re.subn(r'(cats|dogs)', 'Pets', "DoGs are a mans best friend", flags=re.IGNORECASE)
print(string_a)
タプルは以下のようになります。
('Pets are a mans best friend', 1)
Patternオブジェクトは同様の
subn()` 関数を含んでいます。
Pattern.subn(repl, string, count)
そして、それはとても似たような方法で使われます。
import re
pattern = re.compile(r'(Cats|Dogs)')
string_a = pattern.subn("Pets", "Dogs are a man's best friend.")
string_b = pattern.subn("Animals", "Cats enjoy sleeping.")
print(string_a)
print(string_b)
この結果
("Pets are a man's best friend.", 1)
('Animals enjoy sleeping.', 1)
結論
Pythonは文字列を扱うための簡単でシンプルな関数を提供します。文字列中の指定した部分文字列をすべて置き換える最も簡単な方法は、 replace()
関数を使用することです。
必要であれば、標準ライブラリの re
モジュールがより多様なツールセットを提供し、パターン検索や大文字小文字を区別しない検索など、よりニッチな問題に利用することができます。