re.subの第2引数に後方参照(\1とか)を用いた文字列を指定する記事はよくみかけるのですが、第2引数に関数(lambda式)を指定する方法を紹介した記事はあまりみないので書くことにしました。
第2引数に関数(lambda式)を指定すると、置換元文字列になにかしらの処理をほどこしたうえで置換先文字列を生成することができます。
re.subを使うさい、以下のように場合分けできます。
- 置換先文字列が一意に決まっている→第2引数に文字列を指定
- 置換元文字列を装飾・省略して置換先文字列にする→第2引数に後方参照を含む文字列を指定
- 置換元文字列を処理して置換先文字列にする→第2引数に関数(lambda式)を指定する
Contents
置換先文字列が一意に決まっている場合
置換先文字列が一意に決まっている場合、re.subの第2引数に文字列を指定します。いちばん単純な場合ですね。
1 2 3 4 |
text = 'りんごが1個。みかんが3個。バナナが5個。' text = re.sub('\d個', '0個', text) print(text) # りんごが0個。みかんが0個。バナナが0個。 |
果物の個数をすべて0個に置換しました。
置換元文字列を装飾・省略して置換先文字列にする
置換元文字列を装飾するには、第2引数に後方参照を含む文字列を指定します。
1 2 3 4 |
text = 'りんごが1個。みかんが3個。バナナが5個。' text = re.sub('(\d)個', '「\\1個」', text) print(text) # りんごが「1個」。みかんが「3個」。バナナが「5個」。 |
果物の個数を括弧で装飾しました。
つぎは置換元文字列を省略してみます。
1 2 3 4 |
text = 'りんごが1個。みかんが3個。バナナが5個。' text = re.sub('(\d)個', '\\1', text) print(text) # りんごが1。みかんが3。バナナが5。 |
果物の個数から「個」を省略しました。
置換元文字列を処理して置換先文字列にする
置換元文字列を処理して置換先文字列にするには、第2引数に関数を指定します。
1 2 3 4 5 6 7 8 |
def add(x): n = int(x.group(1)) + 1 return str(n) + '個' text = 'りんごが1個。みかんが3個。バナナが5個。' text = re.sub('(\d)個', add, text) print(text) # りんごが2個。みかんが4個。バナナが6個。 |
果物の個数を1個ずつ増やしました。このようにre.subの第2引数に関数を指定することで置換元を処理することができます。関数を定義するさいのポイントは、
- 引数としてマッチオブジェクトがわたってくる
- マッチオブジェクトのgroupメソッドでマッチした部分を取り出して処理する
- 文字列をreturnする(数値をreturnすると例外になります)
- returnした文字列が置換先文字列になる
[affi id=3]
lambda式で簡潔に書く
複雑な処理をするなら関数を定義して第2引数にわたすしかないですが、かんたんな処理であればlambda式を使えば簡潔に書けます。lambda式は1行で書ける無名関数みたいなものです。
1 2 3 4 |
text = 'りんごが1個。みかんが3個。バナナが5個。' text = re.sub('(\d)個', lambda x: str(int(x.group(1)) + 1) + '個', text) print(text) # りんごが2個。みかんが4個。バナナが6個。 |
実用例:半角カナ→全角カナに変換
実用的な例として半角カナを全角カナに変換する例を紹介します。jaconvは日本語の文字種変換をしてくれるモジュールで、pipでインストールできます。
1 2 3 4 5 6 7 |
import re import jaconv text = 'リンゴが1個。パインが3個。バナナが5個。' text = re.sub("([ヲ-ン][゚゙]?[ヲ-ン゚゙]*)", lambda m: jaconv.h2z(m.group(1)), text) print(text) # リンゴが1個。パインが3個。バナナが5個。 |
リンゴ→リンゴ、パイン→パイン、バナナ→バナナに変換しています。
ついでに
map関数を使い、ひとつの文字列ではなく配列(リスト)に入っている文字列の半角カナを全角カナに変換する例も紹介しておきます。
1 2 3 4 5 6 7 |
import re import jaconv fruits = ['リンゴ', 'パイン', 'バナナ'] fruits = map(lambda x: jaconv.h2z(x), fruits) print(list(fruits)) # ['リンゴ', 'パイン', 'バナナ'] |
map関数とおなじようにre.subの引数にも関数を指定できる、とつなげると覚えやすいかもしれません。自分自身がそうやって覚えたので紹介してみました。
蛇足ではありますがmap関数の場合、lambda式で書くまでもなく以下のほうがさらに簡潔ですね。
1 2 3 4 5 6 7 |
import re import jaconv fruits = ['リンゴ', 'パイン', 'バナナ'] fruits = map(jaconv.h2z, fruits) print(list(fruits)) # ['リンゴ', 'パイン', 'バナナ'] |
以上です。