5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

MicroAd (マイクロアド)Advent Calendar 2024

Day 8

re.subで柔軟に文字列置換 #Python

Last updated at Posted at 2024-12-07

Pythonでの文字列置換といえばreplaceですよね。
99%の場面ではこれで問題ないですが、ごく稀に特殊な文字列置換をしたい場面が発生します。
置換対象の文字列の内容によって置換する文字列を変えたいときに役に立つのがre.subです。

長いことPythonを使ってきましたがそんなことができることを知らなくて衝撃を受けたので記事に残しておきます。

いくつか具体的なパターンを見ていきましょう。
以下のパターンでは全て<>で囲まれた部分を置換していきます。
使用している正規表現<.*?><>で囲まれた部分に最短一致します。

置換対象文字列から生成

置換後の文字列がマッチした文字列から関数で生成できる値なら、以下のように置換できます。

def repl(match_obj):
    # マッチした文字列の前後の`<>`を取り除く
    match_str = match_obj.group(0)[1:-1]
    idx = int(match_str)
    if idx % 15 == 0:
        return 'FizzBuzz'
    elif idx % 3 == 0:
        return 'Fizz'
    elif idx % 5 == 0:
        return 'Buzz'
    else:
        return match_str

text = '''when 1 then <1>,
when 3 then <3>,
when 5 then <5>,
when 15 then <15>'''

print(re.sub('<.*?>', repl, text))

出力は以下になります。
関数repl<>内の数値によって置換内容を変えています。

when 1 then 1,
when 3 then Fizz,
when 5 then Buzz,
when 15 then FizzBuzz

辞書を使って置換

辞書でもリストでもいいですが、置換の関数に引数を渡したい場合のパターンです。
置換に使う関数だけをre.subに渡すのでそのままだとマッチしたオブジェクトしか引数として受け取れません。
ラムダ式で引数を渡すことができます。

def repl(match_obj, dct):
    # マッチした文字列の前後の`<>`を取り除く
    match_str = match_obj.group(0)[1:-1]
    return dct[match_str]

user_info = {
    'name': 'John',
    'age': '25',
    'country': 'Japan'
}
text = '''My name is <name>.
I am <age> years old.
I am from <country>.
Please call me <name>.'''

print(re.sub('<.*?>', lambda x: repl(x, user_info), text))
My name is John.
I am 25 years old.
I am from Japan.
Please call me John.

日時のフォーマットを置換

さっきとやっていることは同じですね。
ラムダ式で渡しています。

from datetime import datetime

def repl(match_obj, dt):
    # マッチした文字列の前後の`<>`を取り除く
    match_str = match_obj.group(0)[1:-1]
    return dt.strftime(match_str)

dt_now = datetime(2024, 12, 8, 9, 10, 11)
text = '''The time now is <%-H:%M:%S>.
Today is <%A>, <%B %-d>th.'''

print(re.sub('<.*?>', lambda x: repl(x, dt_now), text))

{}で囲んでいればformatで普通にできるのでそっちがいいと思いますが、自力でも頑張れます。
%-Hとかで0埋めしない表記ができますが、ここがハイフンでいけるかは環境に依存するようです。

The time now is 9:10:11.
Today is Sunday, December 8th.

おわりに

今回挙げた例だと実感しきれないかもしれないですが、re.subを使うことでコードがシンプルになった経験があったのでその感動を伝えたかったというただそれだけです。

5
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?