やりたいこと
- あるテキストの中で、正規表現にマッチした文字列をその内容に基づいて一つずつ置換し、その置換後のテキストを得たい。
- 簡単な例
- もとのテキスト:
aaa <<hoge>> bbb <<fuga>> ccc <<hoge>>
- 置換方法:
-
<<hoge>>
=>APPLE
-
<<fuga>>
=>BANANA
-
- 得たいテキスト:
aaa APPLE bbb BANANA ccc APPLE
- もとのテキスト:
実装
追記:コメントをいただき、 re.sub()
で簡単に実装できることがわかったので、修正しました。コメントをくださった方、ありがとうございます!
import re
def my_replace(match):
"""マッチした文字列に基づいて置換後の文字列を返却する。"""
return "APPLE" if match[0] == "<<hoge>>" else "BANANA"
input_text = "aaa <<hoge>> bbb <<fuga>> ccc <<hoge>>"
result_text = re.sub(r"<<.+?>>", my_replace, input_text)
assert result_text == "aaa APPLE bbb BANANA ccc APPLE"
もともとの実装
import re
def my_replace(match_str):
"""マッチした文字列に基づいて置換後の文字列を返却する。"""
key = match_str[2:-2]
if key == "hoge":
return "APPLE"
return "BANANA"
# 置換したい文字列の正規表現
pattern = re.compile(r"(<<.+?>>)")
# もとのテキスト
input_text = "aaa <<hoge>> bbb <<fuga>> ccc <<hoge>>"
# 得たいテキスト(を格納するための変数)
result_text = ""
# 置換処理(やっていることはシンプルで、マッチした文字列をひとつずつ置換しながら、もとのテキストを連結している)
last_end = 0
for m in re.finditer(pattern, input_text):
result_text += input_text[last_end:m.start()]
result_text += my_replace(m.group())
last_end = m.end()
result_text += input_text[last_end:]
# 結果
assert result_text == "aaa APPLE bbb BANANA ccc APPLE"
備考
-
単に正規表現にマッチした文字列を一括で置換するだけなら.replace()
やre.sub()
を使えばOKなのだが、 マッチした文字列の内容に応じて置換後の文字列を変更したい というようなケースでは、.replace()
やre.sub()
を用いるのは難しい。(上記「簡単な例」なら.replace("<<hoge>>", "APPLE").replace("<<fuga>>", "BANANA")
でも実現可能なのだが、あくまで「簡単な例」なので・・・。)
- 追記:
re.sub()
は第2引数に文字列だけでなく関数も取ることができるので、それで実現可能。