言語処理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の内部リンクマークアップを除去し,テキストに変換せよ(参考: マークアップ早見表).
####出来上がったコード:
# 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ポンド (£)')
('通貨コード', '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 非移植(日本語訳)です。