言語処理100本ノック 2015「第3章: 正規表現」の26本目「強調マークアップの除去」記録です。
今回から28本目までは正規表現でマークアップ除去をしていきます。今回は**sub
関数を使った除去(置換)**を学びます。
参考リンク
リンク | 備考 |
---|---|
026.強調マークアップの除去.ipynb | 回答プログラムのGitHubリンク |
素人の言語処理100本ノック:26 | 多くのソース部分のコピペ元 |
ゼロから覚えるPython正規表現の基本とTips | 当ノックで学習した内容を整理しました |
正規表現 HOWTO | Python公式の正規表現How To |
re --- 正規表現操作 | Python公式のreパッケージ説明 |
Help:早見表 | Wikipediaの代表的なマークアップの早見表 |
環境
種類 | バージョン | 内容 |
---|---|---|
OS | Ubuntu18.04.01 LTS | 仮想で動かしています |
pyenv | 1.2.15 | 複数Python環境を使うことがあるのでpyenv使っています |
Python | 3.6.9 | pyenv上でpython3.6.9を使っています 3.7や3.8系を使っていないことに深い理由はありません パッケージはvenvを使って管理しています |
上記環境で、以下のPython追加パッケージを使っています。通常のpipでインストールするだけです。
種類 | バージョン |
---|---|
pandas | 0.25.3 |
第3章: 正規表現
学習内容
Wikipediaのページのマークアップ記述に正規表現を適用することで,様々な情報・知識を取り出します.
正規表現, JSON, Wikipedia, InfoBox, ウェブサービス
ノック内容
Wikipediaの記事を以下のフォーマットで書き出したファイルjawiki-country.json.gzがある.
- 1行に1記事の情報がJSON形式で格納される
- 各行には記事名が"title"キーに,記事本文が"text"キーの辞書オブジェクトに格納され,そのオブジェクトがJSON形式で書き出される
- ファイル全体はgzipで圧縮される
以下の処理を行うプログラムを作成せよ.
26. 強調マークアップの除去
25の処理時に,テンプレートの値からMediaWikiの強調マークアップ(弱い強調,強調,強い強調のすべて)を除去してテキストに変換せよ(参考: マークアップ早見表).
課題補足(「強調マークアップ」について)
Help:早見表によると「強調マークアップ」は以下の3種類です。
種類 | 書式 | 例 |
---|---|---|
他との区別(斜体) | シングルクォート2つで囲む | ''他との区別'' |
強調(太字) | シングルクォート3つで囲む | '''強調''' |
斜体と強調 | シングルクォート5つで囲む | '''''斜体と強調''''' |
ファイル内の以下の部分を正規表現で抽出します。今回の対象には「強調(太字)」しかないようです。
"|確立形態4 = 現在の国号「'''グレートブリテン及び北アイルランド連合王国'''」に変更\n
回答
回答プログラム 026.強調マークアップの除去.ipynb
from collections import OrderedDict
from pprint import pprint
import re
import pandas as pd
def extract_by_title(title):
df_wiki = pd.read_json('jawiki-country.json', lines=True)
return df_wiki[(df_wiki['title'] == title)]['text'].values[0]
wiki_body = extract_by_title('イギリス')
basic = re.search(r'''
^\{\{基礎情報.*?\n #検索語句(\はエスケープ処理)、非キャプチャ、非貪欲
(.*?) #任意の文字列
\}\} #検索語句(\はエスケープ処理)
$ #文字列の末尾
''', wiki_body, re.MULTILINE+re.VERBOSE+re.DOTALL)
templates = OrderedDict(re.findall(r'''
^\| # \はエスケープ処理、非キャプチャ
(.+?) # キャプチャ対象(key)、非貪欲
\s* # 空白文字0文字以上
= # 検索語句、非キャプチャ
\s* # 空白文字0文字以上
(.+?) # キャプチャ対象(Value)、非貪欲
(?: # キャプチャ対象外のグループ開始
(?=\n\|) # 改行(\n)+'|'の手前(肯定の先読み)
| (?=\n$) # または、改行(\n)+終端の手前(肯定の先読み)
) # キャプチャ対象外のグループ終了
''', basic.group(1), re.MULTILINE+re.VERBOSE+re.DOTALL))
# マークアップ除去
def remove_markup(string):
# 強調マークアップの除去
replaced = re.sub(r'''
(\'{2,5}) # 2〜5個の'(マークアップの開始)
(.*?) # 任意の1文字以上(対象の文字列)
(\1) # 1番目のキャプチャと同じ(マークアップの終了)
''', r'\2', string, flags=re.MULTILINE+re.VERBOSE)
return replaced
for i, (key, value) in enumerate(templates.items()):
replaced = remove_markup(value)
templates[key] = replaced
# 変わったものを表示
if value != replaced:
print(i, key)
print('変更前\t', value)
print('変更後\t', replaced)
print('----')
pprint(templates)
回答解説
今回のメインは以下の部分です。sub
関数を使って「強調マークアップ」の除去(置換)をしています。4つ目の引数にcount
があるのでflags
(コンパイルフラグ)を渡すときには名前を明示する必要があります。count
に気づかずに必死でコンパイルフラグを渡した気になっていて、うまく行かずに30分ほど無駄にしました・・・
replaced = re.sub(r'''
(\'{2,5}) # 2〜5個の'(マークアップの開始)
(.*?) # 任意の1文字以上(対象の文字列)
(\1) # 1番目のキャプチャと同じ(マークアップの終了)
''', r'\2', string, flags=re.MULTILINE+re.VERBOSE)
sub
関数は文字置換をします。引数の順に1. 正規表現パターン、2. 置換後の文字列、3. 置換対象文字列です。
>>> re.sub(r'置換対象', '置換済', '置換対象 対象外 置換対象')
'置換済 対象外 置換済'
ちなみに「確立形態4」の値が変更前と後で以下のようになります。
41 確立形態4
変更前 現在の国号「'''グレートブリテン及び北アイルランド連合王国'''」に変更
変更後 現在の国号「グレートブリテン及び北アイルランド連合王国」に変更
----
出力結果(実行結果)
プログラム実行すると以下の結果が出力されます。まだ残っているマークアップは27、28本目で除去します。
OrderedDict([('略名', 'イギリス'),
('日本語国名', 'グレートブリテン及び北アイルランド連合王国'),
('公式国名',
'{{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年)|1707年連合法]]まで)'),
('確立年月日1', '[[927年]]/[[843年]]'),
('確立形態2', '[[グレートブリテン王国]]建国<br />([[連合法 (1707年)|1707年連合法]])'),
('確立年月日2', '[[1707年]]'),
('確立形態3',
'[[グレートブリテン及びアイルランド連合王国]]建国<br />([[連合法 (1800年)|1800年連合法]])'),
('確立年月日3', '[[1801年]]'),
('確立形態4', '現在の国号「グレートブリテン及び北アイルランド連合王国」に変更'),
('確立年月日4', '[[1927年]]'),
('通貨', '[[スターリング・ポンド|UKポンド]] (£)'),
('通貨コード', 'GBP'),
('時間帯', '±0'),
('夏時間', '+1'),
('ISO 3166-1', 'GB / GBR'),
('ccTLD', '[[.uk]] / [[.gb]]<ref>使用は.ukに比べ圧倒的少数。</ref>'),
('国際電話番号', '44'),
('注記', '<references />')])