動機
青空文庫をスクレイピングして, 自然言語処理を行おうとしていましたが, ルビを振ってくれる<ruby>のタグが邪魔でした. そこで, 正規表現を活かして, わかりやすく<ruby>タグを漢字に直していきます.
以下では, まずコードの全体像を示し, 次に解説を行います.
コード
import re
def erase_ruby(text: str) -> str:
rubyre = re.compile(
r"""<ruby>[\s\S]*?
<rb>(?P<kanji>[\s\S]+?)</rb>[\s\S]*? # 漢字
<rt>(?P<kana>[\s\S]+?)</rt>[\s\S]*? # かな
</ruby>""",
re.VERBOSE
)
text = rubyre.sub(r"\g<kanji>", text)
return text
# 青空文庫収録の偽悪病患者
# https://www.aozora.gr.jp/cards/001872/files/61288_76523.html より
text = """お兄様だけれど、<ruby><rb>喬子</rb><rp>(</rp><rt>きょうこ</rt><rp>)</rp></ruby>、今度の御手紙だけはよく判んない。"""
print(erase_ruby(text))
$ py eraseRuby.py
お兄様だけれど、喬子、今度の御手紙だけはよく判んない。
解説
Pythonでは, re.VERBOSEフラグを使うことで正規表現に空白を入れたり, 正規表現にコメントを書いたりすることができます. これを使って, <ruby>タグにマッチするよう作った正規表現は以下のようになります.
rubyre = re.compile(
r"""<ruby>[\s\S]*?
<rb>(?P<kanji>[\s\S]+?)</rb>[\s\S]*? # 漢字
<rt>(?P<kana>[\s\S]+?)</rt>[\s\S]*? # かな
</ruby>""",
re.VERBOSE
)
コード内に出てきた(?P<kanji> ... )
の表現について, これは名前付きグループと呼ばれるものです.
普通のグループ化はgroup(0)
のように数字で取り出しますが, 名前付きグループを使えばgroup("kanji")
のように, 文字列で取り出すことができるようになるので, 可読性向上につながると考えられます.
次に, <ruby>タグ全体を<rb>タグの中身と置き換えることで目的を達成します.これにはre.sub関数を用います.
re.sub("\g<kanji>", text)
Pythonの置換関数は高性能で, 第一引数には文字列、または関数, 第二引数には処理する文字列を入れます.
第一引数に\g<...>を含む文字列を入れたとき, ...の部分をグループ名としたグループが実際には置換されます.
感想
ドキュメント, 暇なときに読んでみると知らない仕様とか書いてあって結構楽しいです。