LoginSignup
5
1

More than 5 years have passed since last update.

素人の言語処理100本ノック:27

Last updated at Posted at 2016-10-25

言語処理100本ノック 2015の挑戦記録です。環境はUbuntu 16.04 LTS + Python 3.5.2 :: Anaconda 4.1.1 (64-bit)です。過去のノックの一覧はこちらからどうぞ。

第3章: 正規表現

Wikipediaの記事を以下のフォーマットで書き出したファイルjawiki-country.json.gzがある.
・1行に1記事の情報がJSON形式で格納される
・各行には記事名が"title"キーに,記事本文が"text"キーの辞書オブジェクトに格納され,そのオブジェクトがJSON形式で書き出される
・ファイル全体はgzipで圧縮される
以下の処理を行うプログラムを作成せよ.

27. 内部リンクの除去

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

出来上がったコード:

main.py
# coding: utf-8
import gzip
import json
import re
fname = 'jawiki-country.json.gz'


def extract_UK():
    '''イギリスに関する記事本文を取得

    戻り値:
    イギリスの記事本文
    '''

    with gzip.open(fname, 'rt') as data_file:
        for line in data_file:
            data_json = json.loads(line)
            if data_json['title'] == 'イギリス':
                return data_json['text']

    raise ValueError('イギリスの記事が見つからない')


def remove_markup(target):
    '''マークアップの除去
    強調マークアップと内部リンクを除去する

    引数:
    target -- 対象の文字列
    戻り値:
    マークアップを除去した文字列
    '''

    # 強調マークアップの除去
    pattern = re.compile(r'''
        (\'{2,5})   # 2〜5個の'(マークアップの開始)
        (.*?)       # 任意の1文字以上(対象の文字列)
        (\1)        # 1番目のキャプチャと同じ(マークアップの終了)
        ''', re.MULTILINE + re.VERBOSE)
    target = pattern.sub(r'\2', target)

    # 内部リンクの除去
    pattern = re.compile(r'''
        \[\[        # '[['(マークアップの開始)
        (?:         # キャプチャ対象外のグループ開始
            [^|]*?  # '|'以外の文字が0文字以上、非貪欲
            \|      # '|'
        )??         # グループ終了、このグループが0か1出現、非貪欲
        ([^|]*?)    # キャプチャ対象、'|'以外が0文字以上、非貪欲(表示対象の文字列)
        \]\]        # ']]'(マークアップの終了)
        ''', re.MULTILINE + re.VERBOSE)
    target = pattern.sub(r'\1', target)

    return target


# 基礎情報テンプレートの抽出条件のコンパイル
pattern = re.compile(r'''
    ^\{\{基礎情報.*?$   # '{{基礎情報'で始まる行
    (.*?)       # キャプチャ対象、任意の0文字以上、非貪欲
    ^\}\}$      # '}}'の行
    ''', re.MULTILINE + re.VERBOSE + re.DOTALL)

# 基礎情報テンプレートの抽出
contents = pattern.findall(extract_UK())

# 抽出結果からのフィールド名と値の抽出条件コンパイル
pattern = re.compile(r'''
    ^\|         # '|'で始まる行
    (.+?)       # キャプチャ対象(フィールド名)、任意の1文字以上、非貪欲
    \s*         # 空白文字0文字以上
    =
    \s*         # 空白文字0文字以上
    (.+?)       # キャプチャ対象(値)、任意の1文字以上、非貪欲
    (?:         # キャプチャ対象外のグループ開始
        (?=\n\|)    # 改行+'|'の手前(肯定の先読み)
        | (?=\n$)   # または、改行+終端の手前(肯定の先読み)
    )           # グループ終了
    ''', re.MULTILINE + re.VERBOSE + re.DOTALL)

# フィールド名と値の抽出
fields = pattern.findall(contents[0])

# 辞書にセット
result = {}
keys_test = []      # 確認用の出現順フィールド名リスト
for field in fields:
    result[field[0]] = remove_markup(field[1])
    keys_test.append(field[0])

# 確認のため表示(確認しやすいようにkeys_testを使ってフィールド名の出現順にソート)
for item in sorted(result.items(),
        key=lambda field: keys_test.index(field[0])):
    print(item)

実行結果:

端末
('略名', 'イギリス')
('日本語国名', 'グレートブリテン及び北アイルランド連合王国')
('公式国名', '{{lang|en|United Kingdom of Great Britain and Northern Ireland}}<ref>英語以外での正式国名:<br/>\n*{{lang|gd|An Rìoghachd Aonaichte na Breatainn Mhòr agus Eirinn mu Thuath}}(スコットランド・ゲール語)<br/>\n*{{lang|cy|Teyrnas Gyfunol Prydain Fawr a Gogledd Iwerddon}}(ウェールズ語)<br/>\n*{{lang|ga|Ríocht Aontaithe na Breataine Móire agus Tuaisceart na hÉireann}}(アイルランド語)<br/>\n*{{lang|kw|An Rywvaneth Unys a Vreten Veur hag Iwerdhon Glédh}}(コーンウォール語)<br/>\n*{{lang|sco|Unitit Kinrick o Great Breetain an Northren Ireland}}(スコットランド語)<br/>\n**{{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/>(フランス語:神と私の権利)')
('国歌', '神よ女王陛下を守り給え')
('位置画像', 'Location_UK_EU_Europe_001.svg')
('公用語', '英語(事実上)')
('首都', 'ロンドン')
('最大都市', 'ロンドン')
('元首等肩書', '女王')
('元首等氏名', 'エリザベス2世')
('首相等肩書', '首相')
('首相等氏名', 'デーヴィッド・キャメロン')
('面積順位', '76')
('面積大きさ', '1 E11')
('面積値', '244,820')
('水面積率', '1.3%')
('人口統計年', '2011')
('人口順位', '22')
('人口大きさ', '1 E7')
('人口値', '63,181,775<ref>[http://esa.un.org/unpd/wpp/Excel-Data/population.htm United Nations Department of Economic and Social Affairs>Population Division>Data>Population>Total Population]</ref>')
('人口密度値', '246')
('GDP統計年元', '2012')
('GDP値元', '1兆5478億<ref name="imf-statistics-gdp">[http://www.imf.org/external/pubs/ft/weo/2012/02/weodata/weorept.aspx?pr.x=70&pr.y=13&sy=2010&ey=2012&scsm=1&ssd=1&sort=country&ds=.&br=1&c=112&s=NGDP%2CNGDPD%2CPPPGDP%2CPPPPC&grp=0&a= IMF>Data and Statistics>World Economic Outlook Databases>By Countrise>United Kingdom]</ref>')
('GDP統計年MER', '2012')
('GDP順位MER', '5')
('GDP値MER', '2兆4337億<ref name="imf-statistics-gdp" />')
('GDP統計年', '2012')
('GDP順位', '6')
('GDP値', '2兆3162億<ref name="imf-statistics-gdp" />')
('GDP/人', '36,727<ref name="imf-statistics-gdp" />')
('建国形態', '建国')
('確立形態1', 'イングランド王国/スコットランド王国<br />(両国とも1707年連合法まで)')
('確立年月日1', '927年/843年')
('確立形態2', 'グレートブリテン王国建国<br />(1707年連合法)')
('確立年月日2', '1707年')
('確立形態3', 'グレートブリテン及びアイルランド連合王国建国<br />(1800年連合法)')
('確立年月日3', '1801年')
('確立形態4', '現在の国号「グレートブリテン及び北アイルランド連合王国」に変更')
('確立年月日4', '1927年')
('通貨', 'UKポンド (&pound;)')
('通貨コード', 'GBP')
('時間帯', '±0')
('夏時間', '+1')
('ISO 3166-1', 'GB / GBR')
('ccTLD', '.uk / .gb<ref>使用は.ukに比べ圧倒的少数。</ref>')
('国際電話番号', '44')
('注記', '<references />')

内部リンク「のみ」の除去

前問remove_markup()を改修しています。
今回ハマったのは、うまく動くようになった!と思って確認していたら、[[ファイル:Royal Coat of Arms of the United Kingdom.svg|85px|イギリスの国章]]といったファイルの指定まで巻き込んでいたことです。そこで、[[]]で括られた範囲に|が0または1個しか出てこないという条件に変更して(ファイルの場合は2個出てくる)、ファイルを巻き込むのを防いでみました。
ただしこれでは、問題21や22で対象になった[[Category:イギリス|*]]などのカテゴリや、マークアップ早見表にある#REDIRECT [[記事名]]といったリダイレクトを巻き込んでしまいますので、ちょっと中途半端です。今回の対象データにはたまたま出てこないので良いのですが、出題の意図には答えられていないかも...

 
28本目のノックは以上です。誤りなどありましたら、ご指摘いただけますと幸いです。


実行結果には、100本ノックで用いるコーパス・データで配布されているデータの一部が含まれます。この第3章で用いているデータのライセンスはクリエイティブ・コモンズ 表示-継承 3.0 非移植日本語訳)です。

5
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1