morikomorou’s blog

自分が学んだことなどの備忘録的なやつ

【python】言語処理100本ノック2020を解く(第3章後半)


はじめに

前回の続きで言語処理100本ノック解いていきたいと思います。

今回は第3章の後半です。正規表現の章やっていきます。




第3章: 正規表現

Wikipediaのページのマークアップ記述に正規表現を適用することで,様々な情報・知識を取り出します.
変数やモジュールは前半で出てきたものを使っており、今回は省略しているので20~24までの過去記事を参照願います。

25. テンプレートの抽出

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

まずは基礎情報の入っている部分の文章を抜き出します
以下の()の個所です

{{基礎情報 国
(ここをtemplateとして抜き出す)
}}

続いて、template内の、=の左側をkey, 右側をvalueとして辞書を作成します。

def read_info(data):
    pattern = r'\{\基礎情報.*?$(.*?)^\}\}$'
    result = re.findall(pattern, data, re.MULTILINE + re.DOTALL)
    template = result[0]
    
    data_info = {}
    pattern = r'^\|(.*?)\s=\s*(.*?)(?:(?=\n\|)|(?=\n$))'
    result = re.findall(pattern, template, re.MULTILINE + re.DOTALL)
    for k, v in result:
        data_info[k] = v
    return data_info

data_info = read_info(data)
for k, v in data_info.items():
    print(k, ':', v)

以下出力です。

略名  : イギリス
日本語国名 : グレートブリテン及び北アイルランド連合王国
公式国名 : {{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}}([[ウェールズ語]])
*{{lang|ga|Ríocht Aontaithe na Breataine Móire agus Tuaisceart na hÉireann}}([[アイルランド語]])
*{{lang|kw|An Rywvaneth Unys a Vreten Veur hag Iwerdhon Glédh}}([[コーンウォール語]])
*{{lang|sco|Unitit Kinrick o Great Breetain an Northren Ireland}}([[スコットランド語]])
**{{lang|sco|Claught Kängrick o Docht Brätain an Norlin Airlann}}、{{lang|sco|Unitet Kängdom o Great Brittain an Norlin Airlann}}(アルスター・スコットランド語)</ref>
国旗画像 : Flag of the United Kingdom.svg
国章画像 : [[ファイル:Royal Coat of Arms of the United Kingdom.svg|85px|イギリスの国章]]
国章リンク : ([[イギリスの国章|国章]])

26. 強調マークアップの除去

25の処理時に,テンプレートの値からMediaWikiの強調マークアップ(弱い強調,強調,強い強調のすべて)を除去してテキストに変換せよ(参考:マークアップ早見表).

先ほど作成した関数を修正します。
強調マークアップは以下の3つなのでそれぞれ'を削除します

  • ''他との区別''
  • '''強調'''
  • '''''斜体と強調'''''
def read_info(data):
    # 基礎情報テンプレートの抽出
    pattern = r'\{\基礎情報.*?$(.*?)^\}\}$'
    result = re.findall(pattern, data, re.MULTILINE + re.DOTALL)
    template = result[0]
    
    # 基礎情報テンプレートから辞書の作成
    data_info = {}
    pattern = r'^\|(.*?)\s=\s*(.*?)(?:(?=\n\|)|(?=\n$))'
    result = re.findall(pattern, template, re.MULTILINE + re.DOTALL)
    for k, v in result:
        data_info[k] = v
    
    # 情報の整形
    for k, v in data_info.items():
        # 強調マークアップの除去(例: ''ああ''->ああ)
        pattern = r"\'{2,5}"
        data_info[k] = re.sub(pattern, '', v)
    return data_info

data_info = read_info(data)
for k, v in data_info.items():
    print(k, ':', v)

出力は長いので最初の数行のみです

略名  : イギリス
日本語国名 : グレートブリテン及び北アイルランド連合王国
公式国名 : {{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}}([[ウェールズ語]])
*{{lang|ga|Ríocht Aontaithe na Breataine Móire agus Tuaisceart na hÉireann}}([[アイルランド語]])
*{{lang|kw|An Rywvaneth Unys a Vreten Veur hag Iwerdhon Glédh}}([[コーンウォール語]])
*{{lang|sco|Unitit Kinrick o Great Breetain an Northren Ireland}}([[スコットランド語]])
**{{lang|sco|Claught Kängrick o Docht Brätain an Norlin Airlann}}、{{lang|sco|Unitet Kängdom o Great Brittain an Norlin Airlann}}(アルスター・スコットランド語)</ref>
国旗画像 : Flag of the United Kingdom.svg
国章画像 : [[ファイル:Royal Coat of Arms of the United Kingdom.svg|85px|イギリスの国章]]
国章リンク : ([[イギリスの国章|国章]])
標語 : {{lang|fr|[[Dieu et mon droit]]}}<br />([[フランス語]]:[[Dieu et mon droit|神と我が権利]])
国歌 : [[女王陛下万歳|{{lang|en|God Save the Queen}}]]{{en icon}}<br />神よ女王を護り賜え<br />{{center|[[ファイル:United States Navy Band - God Save the Queen.ogg]]}}
地図画像 : Europe-UK.svg
位置画像 : United Kingdom (+overseas territories) in the World (+Antarctica claims).svg
公用語 : [[英語]]

27. 内部リンクの除去

26の処理に加えて,テンプレートの値からMediaWikiの内部リンクマークアップを除去し,テキストに変換せよ(参考: マークアップ早見表).

これも先ほどの関数を修正します。
内部リンクは下記のようなパターンで修正します

  • [ [記事名] ]->記事名
  • [ [記事名|表示文字 ] ]->表示文字
def read_info(data):
    # 基礎情報テンプレートの抽出
    pattern = r'\{\基礎情報.*?$(.*?)^\}\}$'
    result = re.findall(pattern, data, re.MULTILINE + re.DOTALL)
    template = result[0]
    
    # 基礎情報テンプレートから辞書の作成
    data_info = {}
    pattern = r'^\|(.*?)\s=\s*(.*?)(?:(?=\n\|)|(?=\n$))'
    result = re.findall(pattern, template, re.MULTILINE + re.DOTALL)
    for k, v in result:
        data_info[k] = v
    
    # 情報の整形
    for k, v in data_info.items():
        # 強調マークアップの除去(例: ''ああ''->ああ)
        pattern = r"\'{2,5}"
        v = re.sub(pattern, '', v)
        
        # 内部リンクの除去1(例: [[記事名]]->記事名)
        pattern = r'\[\[(?!ファイル)([^\|]+?)\]\]'
        v = re.sub(pattern, r'\1', v)
        
        # 内部リンクの除去2(例: [[記事名|表示文字]]->表示文字)
        pattern = r'\[\[(?!ファイル)(?:[^\|]*)\|*(.*?)\]\]'
        v = re.sub(pattern, r'\1', v)
        
        data_info[k] = v
    return data_info

data_info = read_info(data)
for k, v in data_info.items():
    print(k, ':', v)

出力は長いので最初の数行のみです

略名  : イギリス
日本語国名 : グレートブリテン及び北アイルランド連合王国
公式国名 : {{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}}(ウェールズ語)
*{{lang|ga|Ríocht Aontaithe na Breataine Móire agus Tuaisceart na hÉireann}}(アイルランド語)
*{{lang|kw|An Rywvaneth Unys a Vreten Veur hag Iwerdhon Glédh}}(コーンウォール語)
*{{lang|sco|Unitit Kinrick o Great Breetain an Northren Ireland}}(スコットランド語)
**{{lang|sco|Claught Kängrick o Docht Brätain an Norlin Airlann}}、{{lang|sco|Unitet Kängdom o Great Brittain an Norlin Airlann}}(アルスター・スコットランド語)</ref>
国旗画像 : Flag of the United Kingdom.svg
国章画像 : [[ファイル:Royal Coat of Arms of the United Kingdom.svg|85px|イギリスの国章]]
国章リンク : (国章)
標語 : {{lang|fr|Dieu et mon droit}}<br />(フランス語:神と我が権利)
国歌 : {{lang|en|God Save the Queen}}{{en icon}}<br />神よ女王を護り賜え<br />{{center|[[ファイル:United States Navy Band - God Save the Queen.ogg]]}}
地図画像 : Europe-UK.svg
位置画像 : United Kingdom (+overseas territories) in the World (+Antarctica claims).svg
公用語 : 英語
首都 : ロンドン(事実上)
最大都市 : ロンドン
元首等肩書 : 女王




28. MediaWikiマークアップの除去

27の処理に加えて,テンプレートの値からMediaWikiマークアップを可能な限り除去し,国の基本情報を整形せよ.

これも先ほどの関数を修正します。
特にどれを削除しろとか指示ないので好きなようにやりましょう。
見やすい感じにできれば何でもいいと思います。

def read_info(data):
    # 基礎情報テンプレートの抽出
    pattern = r'\{\基礎情報.*?$(.*?)^\}\}$'
    result = re.findall(pattern, data, re.MULTILINE + re.DOTALL)
    template = result[0]
    
    # 基礎情報テンプレートから辞書の作成
    data_info = {}
    pattern = r'^\|(.*?)\s=\s*(.*?)(?:(?=\n\|)|(?=\n$))'
    result = re.findall(pattern, template, re.MULTILINE + re.DOTALL)
    for k, v in result:
        data_info[k] = v
    
    # 情報の整形
    for k, v in data_info.items():
        # 強調マークアップの除去(例: ''ああ''->ああ)
        pattern = r"\'{2,5}"
        v = re.sub(pattern, '', v)
        
        # 内部リンクの除去1(例: [[記事名]]->記事名)
        pattern = r'\[\[(?!ファイル)([^\|]+?)\]\]'
        v = re.sub(pattern, r'\1', v)
        
        # 内部リンクの除去2(例: [[記事名|表示文字]]->表示文字)
        pattern = r'\[\[(?!ファイル)(?:[^\|]*)\|*(.*?)\]\]'
        v = re.sub(pattern, r'\1', v)
        
        # MediaWikiマークアップの除去1(例: {{~~}}->)
        pattern = r'\{\{[^\|]+?\}\}'
        v = re.sub(pattern, '', v)
        
        # MediaWikiマークアップの除去2(例: {{(lang|仮リンク)~|~|ああ}}->ああ)
        pattern = r'\{\{(?:lang|仮リンク)(?:.*?)\|([^\|]*?)\}\}'
        v = re.sub(pattern, r'\1', v)
        
        # MediaWikiマークアップの除去3(例: {{上記以外}}->)
        pattern = r'\{\{.+?\}\}'
        v = re.sub(pattern, '', v)
        
        # MediaWikiマークアップの除去4(例: <~~> -> )
        pattern = r'<.+?>'
        v = re.sub(pattern, '', v)
        
        # MediaWikiマークアップの除去5(例: [[ファイル:~~|...|dfdk]] -> ~~)
        pattern = r'\[\[ファイル:([^\|]+?)\|.*?\]\]'
        v = re.sub(pattern, r'\1', v)
        
        # MediaWikiマークアップの除去6(例: [~~~] -> )
        pattern = r'\[.+?\]'
        v = re.sub(pattern, '', v)
        
        data_info[k] = v
    return data_info

data_info = read_info(data)
for k, v in data_info.items():
    print(k, ':', v)

最後なので出力全文載せておきます

略名  : イギリス
日本語国名 : グレートブリテン及び北アイルランド連合王国
公式国名 : United Kingdom of Great Britain and Northern Ireland英語以外での正式国名:
*An Rìoghachd Aonaichte na Breatainn Mhòr agus Eirinn mu Thuath(スコットランド・ゲール語)
*Teyrnas Gyfunol Prydain Fawr a Gogledd Iwerddon(ウェールズ語)
*Ríocht Aontaithe na Breataine Móire agus Tuaisceart na hÉireann(アイルランド語)
*An Rywvaneth Unys a Vreten Veur hag Iwerdhon Glédh(コーンウォール語)
*Unitit Kinrick o Great Breetain an Northren Ireland(スコットランド語)
**Claught Kängrick o Docht Brätain an Norlin Airlann、Unitet Kängdom o Great Brittain an Norlin Airlann(アルスター・スコットランド語)
国旗画像 : Flag of the United Kingdom.svg
国章画像 : Royal Coat of Arms of the United Kingdom.svg
国章リンク : (国章)
標語 : Dieu et mon droit(フランス語:神と我が権利)
国歌 : God Save the Queen神よ女王を護り賜え
地図画像 : Europe-UK.svg
位置画像 : United Kingdom (+overseas territories) in the World (+Antarctica claims).svg
公用語 : 英語
首都 : ロンドン(事実上)
最大都市 : ロンドン
元首等肩書 : 女王
元首等氏名 : エリザベス2世
首相等肩書 : 首相
首相等氏名 : ボリス・ジョンソン
他元首等肩書1 : 貴族院議長
他元首等氏名1 : ノーマン・ファウラー
他元首等肩書2 : 庶民院議長
他元首等氏名2 : Lindsay Hoyle
他元首等肩書3 : 最高裁判所長官
他元首等氏名3 : ブレンダ・ヘイル
面積順位 : 76
面積大きさ : 1 E11
面積値 : 244,820
水面積率 : 1.3%
人口統計年 : 2018
人口順位 : 22
人口大きさ : 1 E7
人口値 : 6643万5600
人口密度値 : 271
GDP統計年元 : 2012
GDP値元 : 1兆5478億
GDP統計年MER : 2012
GDP順位MER : 6
GDP値MER : 2兆4337億
GDP統計年 : 2012
GDP順位 : 6
GDP値 : 2兆3162億
GDP/人 : 36,727
建国形態 : 建国
確立形態1 : イングランド王国/スコットランド王国(両国とも1707年合同法まで)
確立年月日1 : 927年/843年
確立形態2 : グレートブリテン王国成立(1707年合同法)
確立年月日2 : 1707年5月1日
確立形態3 : グレートブリテン及びアイルランド連合王国成立(1800年合同法)
確立年月日3 : 1801年1月1日
確立形態4 : 現在の国号「グレートブリテン及び北アイルランド連合王国」に変更
確立年月日4 : 1927年4月12日
通貨 : UKポンド (£)
通貨コード : GBP
時間帯 : ±0
夏時間 : +1
ISO 3166-1 : GB / GBR
ccTLD : .uk / .gb使用は.ukに比べ圧倒的少数。
国際電話番号 : 44
注記 : 

29. 国旗画像のURLを取得する

テンプレートの内容を利用し,国旗画像のURLを取得せよ.(ヒント: MediaWiki APIのimageinfoを呼び出して,ファイル参照をURLに変換すればよい)

ヒントの通り、apiを使用します。
requestsを使ってapiのurlにアクセスして情報を取得します。
取得した情報から正規表現で画像のurlのみ取り出す形です。

import requests
fig_name = data_info['国旗画像'].replace(' ', '_')
url = 'https://commons.wikimedia.org/w/api.php?action=query&titles=File:' + fig_name + '&prop=imageinfo&iiprop=url&format=json'
data = requests.get(url).text
print(data)
print('\n')

pattern = r'\"url\":\"([^\"]+?)\"'
res_url = re.findall(pattern, data)
print(res_url[0])
{"continue":{"iistart":"2019-09-10T16:52:58Z","continue":"||"},"query":{"normalized":[{"from":"File:Flag_of_the_United_Kingdom.svg","to":"File:Flag of the United Kingdom.svg"}],"pages":{"347935":{"pageid":347935,"ns":6,"title":"File:Flag of the United Kingdom.svg","imagerepository":"local","imageinfo":[{"url":"https://upload.wikimedia.org/wikipedia/commons/a/ae/Flag_of_the_United_Kingdom.svg","descriptionurl":"https://commons.wikimedia.org/wiki/File:Flag_of_the_United_Kingdom.svg","descriptionshorturl":"https://commons.wikimedia.org/w/index.php?curid=347935"}]}}}}

https://upload.wikimedia.org/wikipedia/commons/a/ae/Flag_of_the_United_Kingdom.svg

おわりに

3章終わりです。
正規表現わけわからなくなってきます。
一気に全パターン抜き出したり、置換したりしようと思わず、置換できるものから順番に置換していくのが心の安らぎにつながります。