hideb

多分技術系の話をするところ。

python 複数の組み合わせパターンで文字列置換

Python で複数の組み合わせパターンに従って文字列を置換する方法。

PHP でいうと

<?php
$orig_text = "AAA BBB CCC DDD";
$result = str_replace(
  ["AAA", "CCC"],
  ["えー", "しー"],
  $orig_text
);

// "えー BBB しー DDD"
echo $result;

みたいなことをやりたい。

Python でもシュッと出来るじゃろ~と思っていたのだが、意外とそうでもなかったのでメモしておく。

方法1 : 単純に繰り返し置換する

orig_text = "AAA BBB CCC DDD"
replacements = {
    "AAA": "えー",
    "CCC": "しー",
}
result = orig_text

for old, new in replacements.items():
    result = result.replace(old, new)

# "えー BBB しー DDD"
print(result)

短くて読みやすいし意図も分かりやすい。

書き捨てのスクリプトだったり、組み合わせパターン数や原文テキストが小規模なら十分だと思う。

ただ、芸術性や魔力が低めなので一流の Pythonista たちは苦い顔をするかもしれない。

方法2 : re.sub() と lambda を駆使する

import re

orig_text = "AAA BBB CCC DDD"
replacements = {
    "AAA": "えー",
    "CCC": "しー",
}
replacements = dict((re.escape(k), v) for k, v in replacements.items())
pattern = re.compile("|".join(replacements.keys()))
result = pattern.sub(lambda m: replacements[re.escape(m.group(0))], orig_text)

# "えー BBB しー DDD"
print(result)

芸術点と魔力が爆発的に上がり、もはやパッと見で何をしてるのかわからない。

順を追って解説を入れると次の通り。

replacements = dict((re.escape(k), v) for k, v in replacements.items())

辞書 replacements について、Key に含まれる正規表現メタ文字列をエスケープしている。

今回の例では Key (=置換元、検索対象) に正規表現のメタ文字は含まれないので、エスケープ後も {"AAA": "えー", "CCC": "しー"} のまま。 もしメタ文字がある場合は {"AA\\[A": "えー", "CC\\-C": "しー"} のようになる。

pattern = re.compile("|".join(replacements.keys()))

置換対象文字列を検索するためのパターンを作る。この例の場合、 patternAAA|CCC となる。

result = pattern.sub(lambda m: replacements[re.escape(m.group(0))], orig_text)

第1引数の lambda 式を使って置換先の文字列を解決し、置換を行う。 lambda の引数には、パターンに関する Match[str] が与えられる。

パターンにマッチした文字列 (m.group(0)) を正規表現メタ文字をエスケープすると replacements の Key になるので、置換後の文字列に解決できる。


スクリプト言語だと冒頭の PHP コードのようなことはサクッとできるイメージがあったけど、Python でいざやろうとしたらちょっとした精神統一が必要だったので備忘録まで。

以上。