言語処理100本ノック 2015 第3章 25〜29


言語処理100本ノック 2015」の「第3章: 正規表現」、25〜29。

25. テンプレートの抽出

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

記事本文を渡すと「基礎情報」テンプレートのフィールド名、値を格納した辞書を返す関数を以下のように作ってみました。

import re


def get_basicinfo(article):
    regex = re.compile(r'^{{基礎情報 国$(.+?)^}}$',
                       flags=(re.MULTILINE | re.DOTALL))
    match = regex.search(article)

    if match:
        content = match.group(1)
        regex2 = re.compile(r'^\|(.+?) = (.+?)(?:(?=\n\|)|(?=\n$))',
                            flags=(re.MULTILINE | re.DOTALL))
        result = {m.group(1): m.group(2) for m in regex2.finditer(content)}
    else:
        result = dict()

    return result

うまく動かなくて調べたりしたところはre.compileに渡しているflagsのre.MULTILINEとre.DOTALL、あと(?=…)のところですかね。

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

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

リンクされている「マークアップ早見表」によると、引用符が2つ、3つ、5つが強調のマークアップの模様。
25で作ったget_basicinfo関数からマークアップ削除用にremove_markup関数を呼び出すようにしてみました。

import re


def remove_markup(s):
    return re.sub(r"('{2,3})|('{5})", '', s)


def get_basicinfo(article):
    regex = re.compile(r'^{{基礎情報 国$(.+?)^}}$',
                       flags=(re.MULTILINE | re.DOTALL))
    match = regex.search(article)

    if match:
        content = match.group(1)
        regex2 = re.compile(r'^\|(.+?) = (.+?)(?:(?=\n\|)|(?=\n$))',
                            flags=(re.MULTILINE | re.DOTALL))
        result = {m.group(1): remove_markup(m.group(2))
                  for m in regex2.finditer(content)}
    else:
        result = dict()

    return result

27. 内部リンクの除去

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

内部リンクマークアップは[[イングランド王国]]という形式か[[連合法 (1707年)|1707年連合法]]という形式。
前者の場合はそのままの文字列に置換すればOK、後者の場合は|以降の部分の文字列に置換、という形。
単純に対応してしまうと、ファイル参照である[[ファイル:Royal Coat of Arms of the United Kingdom.svg|85px|イギリスの国章]]という形式にもヒットしてしまうので、そこは考慮して以下のようにしてみました。

import re


def remove_markup(s):
    s = re.sub(r"('{2,3})|('{5})", '', s)
    s = re.sub(r'\[\[(?:[^]|]+?\|)?([^|]+?)\]\]', r'\1', s)
    return s

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

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

あくまでも今回の例文で、のみの対応ですが、以下対応してみました。

  • [[ファイル:Royal Coat of Arms of the United Kingdom.svg|85px|イギリスの国章]]→イギリスの国章
  • {{lang|fr|Dieu et mon droit}}→Dieu et mon droit
  • <br/>→(空白文字)
  • abc<ref>hogehoge</ref>→abc hogehoge
  • <references />→(削除)
  • [http://abc.org/hoge.htm A B>C]→A B>C
import re


def remove_markup(s):
    s = re.sub(r"('{2,3})|('{5})", '', s)
    s = re.sub(r'\[\[(?:[^]|]+?\|)?([^|]+?)\]\]', r'\1', s)
    s = re.sub(r'{{lang\|[a-z]+\|([^}]+?)}}', r'\1', s)
    s = re.sub(r'\[\[ファイル:[^|]+\|[^|]+\|([^]]+?)\]\]', r'\1', s)
    s = re.sub('<br */>', ' ', s)
    s = re.sub(r'<ref( [^>]+?)?>', ' ', s)
    s = re.sub('</ref>', '', s)
    s = re.sub('<references />', '', s)
    s = re.sub(r'\[http://[^ ]+ ([^]]+?)\]', r'\1', s)
    return s

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

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

テンプレートの「国旗画像」の値からURLを取得する関数を以下のように作ってみました。

import json
import urllib.request
import urllib.parse


def get_url(filename):
    params = {'action': 'query', 'titles': 'File:' + filename,
              'prop': 'imageinfo', 'iiprop': 'url', 'format': 'json'}
    encoded_params = urllib.parse.urlencode(params)

    with urllib.request.urlopen('http://ja.wikipedia.org/w/api.php?' +
                                encoded_params) as res:
        url = json.loads(res.read().decode('utf-8')
                         )['query']['pages']['-1']['imageinfo'][0]['url']
        return url

新しく出てきたところはurllibを使っている点ですね。
あくまで今回の件のみターゲットとした対応なので、汎用的にはなっていないと思います…

スポンサーリンク

フォローする

スポンサーリンク