👩‍💻

言語処理100本ノック 2020 (Rev 2) 第3章: 正規表現 25. テンプレートの抽出

2023/01/09に公開約2,300字

問題

25. テンプレートの抽出

記事中に含まれる「基礎情報」テンプレートのフィールド名と値を抽出し,辞書オブジェクトとして格納せよ.

solution25.py
import pandas as pd
import re

df_j = pd.read_json('chapter03/jawiki-country.json.gz', lines=True, compression='infer')
text_uk = df_j.query('title=="イギリス"')['text'].values[0]

template_text = re.findall(r'\{\{基礎情報 (.+?^}\})', text_uk, re.MULTILINE+re.DOTALL)[0]
template = dict(re.findall("\|(.+?) *= *(.+?)\n(?=\||})", template_text, re.MULTILINE+re.DOTALL))

for t in template:
    print(t, template[t])
output
略名 イギリス
日本語国名 グレートブリテン及び北アイルランド連合王国
公式国名 {{lang|en|United Kingdom of Great Britain and Northern Ireland}}<ref>英語以外での正式国名:<br />
*{{lang|gd|An Rìoghachd Aonaichte na Breatainn Mhòr agus Eirinn mu Thuath}}([[スコットランド・ゲール語]])
*{{lang|cy|Teyrnas Gyfunol Prydain Fawr a Gogledd Iwerddon}}([[ウェールズ語]])

この問題では、正規表現を用いて基礎情報[1]に該当する箇所を取り出します。

r'\{\{基礎情報 (.+?^}\})': \{{ を表すエスケープシーケンスです。2つ並べることで、{{ を表しています。それに続いて、基礎情報 という文字列が続きます。次に、(.+?^}\}) というパターンがあります。これは、正規表現のグループを表す括弧で囲まれています。その中で、. は任意の1文字を表します。+ は1回以上の繰り返しを意味します。.+ とすることで、任意の1文字以上の連続する文字列を表しています。さらに、.+? とすることで、非貪欲マッチ (non-greedy match) を行うことを指定しています。修飾子の後に ? を追加すると、 非貪欲 (あるいは 最小と言われてる) のマッチが行われ、できるだけ少ない文字にマッチします。つまり、.+? の中にある ^}} の間に最短でマッチするようにしています。^は(キャレット) 文字列の先頭にマッチし、 MULTILINEモード[2]では各改行の直後にもマッチします。

re.MULTILINEとあわせて利用しているre.DOTALLですが、. 特殊文字を、改行を含むあらゆる文字にマッチさせます。このフラグがなければ、. は、改行 以外の あらゆる文字とマッチします。

'\|(.+?) *= *(.+?)\n(?=\||})': \| は、| を表すエスケープシーケンスです。それに続いて、(.+?) というパターンがあります。これは、先ほどと同様に、任意の1文字以上の連続する文字列を表しています。次に、スペース文字が0個以上続きます ( *= *)。さらに、次の (.+?) というパターンがあります。これも、先ほどと同様に、任意の1文字以上の連続する文字列を表しています。最後に、改行文字 (\n) が続きます。そして、(?=\||}) というパターンがあります。これは、正規表現の lookahead assertion を表しています。このパターンを使用することで、現在の位置の後ろに、| または } のいずれかが存在するかどうかを確認することができます。

https://github.com/kurokawa5/nlp100_2020/blob/main/chapter03/solution25.py

参考記事

第3章: 正規表現
re --- 正規表現操作
Python正規表現
regex101
先読みと後読み(Lookahead/lookbehind)

脚注
  1. Template:基礎情報 国 ↩︎

  2. re.MULTILINE ↩︎

Discussion

ログインするとコメントできます