読者です 読者をやめる 読者になる 読者になる

北野坂備忘録

主にインストールやプログラミングのメモを載せています。

言語処理100本ノック 2015年版 (20~29)

第3章は正規表現

20. JSONデータの読み込み

Wikipedia記事のJSONファイルを読み込み,「イギリス」に関する記事本文を表示せよ.問題21-29では,ここで抽出した記事本文に対して実行せよ.

#!/usr/bin/env python

import codecs
import json

fin = codecs.open('jawiki-country.json', 'r', 'utf_8')

if __name__ == "__main__":
  for line in fin:
    jsonData = json.loads(line)
    if jsonData["title"] == "イギリス":
      with codecs.open('UK.txt', 'w', 'utf_8') as file:
        file.write(jsonData["text"])

jsonを使っていきます。一行ごとに処理していかないといけないのが罠か。

21. カテゴリ名を含む行を抽出

 記事中でカテゴリ名を宣言している行を抽出せよ.

 カテゴリ名とは何か、が自明ではない。
 とりあえずCategory:という単語のある行を正規表現を使って抽出

#!/usr/bin/env python

import codecs
import re

fin = codecs.open('UK.txt', 'r', 'utf_8')

if __name__ == "__main__":
  for line in fin:
    if re.search("Category:",line):
      print(line, end="")
  print("")

結果

[[Category:イギリス|*]]
[[Category:英連邦王国|*]]
[[Category:G8加盟国]]
[[Category:欧州連合加盟国]]
[[Category:海洋国家]]
[[Category:君主国]]
[[Category:島国|くれいとふりてん]]
[[Category:1801年に設立された州・地域]]

「くれいとふりてん」がフリテンの一種みたいでかわいらしい。

22. カテゴリ名の抽出

 記事のカテゴリ名を(行単位ではなく名前で)抽出せよ.

 カテゴリが1行に複数入っていても対応できるようにしたけど意味あるかなコレ

#!/usr/bin/env python

import codecs
import re

fin = codecs.open('UK.txt', 'r', 'utf_8')

if __name__ == "__main__":
  for line in fin:
    if re.search("Category:",line):
      r = re.findall(r'\[\[Category:.*\]\]',line)
      for src in r:
        src = re.sub("\[\[Category:","",src)
        src = re.sub("\]\]","",src)
        print(src)

結果

イギリス|*
英連邦王国|*
G8加盟国
欧州連合加盟国
海洋国家
君主国
島国|くれいとふりてん
1801年に設立された州・地域
23. セクション構造

 記事中に含まれるセクション名とそのレベル(例えば"== セクション名 =="なら1)を表示せよ.

 地理が3,気候が3.1
 それぞれ=が2,=が3
 イギリスのポピュラー音楽だけ====

#!/usr/bin/env python

import codecs
import re

fin = codecs.open('UK.txt', 'r', 'utf_8')

if __name__ == "__main__":
  for line in fin:
    if re.search("\={4}",line):
      line = re.sub('\={4}$',' 3',line)
      line = re.sub('\={4}','',line)
      print(line,end="")
    elif re.search("\={3}",line):
      line = re.sub('\={3}$',' 2',line)
      line = re.sub('\={3}','',line)
      print(line,end="")
    elif re.search("\=\=",line):
      line = re.sub('\=\=$',' 1',line)
      line = re.sub('\=\=','',line)
      print(line,end="")

ダサイ。ダサ過ぎる。ただ再帰とか使うと何しているのか分かり辛くなる。

24. ファイル参照の抽出

 記事から参照されているメディアファイルをすべて抜き出せ.

 こちらこそ1行に何回か入っている可能性があるのでリストにする。

#!/usr/bin/env python

import codecs
import re

fin = codecs.open('UK.txt', 'r', 'utf_8')
l=[]

if __name__ == "__main__":
  for line in fin:
    if re.search("File:",line):
      r = re.findall(r'\[\[File:.*\]\]',line)
      for src in r:
        src = re.sub("\[\[File:","",src)
        src = re.sub("\]\]","",src)
        l = re.split('\|',src)
        print(l[0])

結果

Battle of Waterloo 1815.PNG
The British Empire.png
Uk topo en.jpg
BenNevis2005.jpg
Elizabeth II greets NASA GSFC employees, May 8, 2007 edit.jpg
Palace of Westminster, London - Feb 2007.jpg
David Cameron and Barack Obama at the G20 Summit in Toronto.jpg
Soldiers Trooping the Colour, 16th June 2007.jpg
Scotland Parliament Holyrood.jpg
London.bankofengland.arp.jpg
City of London skyline from London City Hall - Oct 2008.jpg
Oil platform in the North SeaPros.jpg
Eurostar at St Pancras Jan 2008.jpg
Heathrow T5.jpg
Anglospeak.svg
25. テンプレートの抽出

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

#!/usr/bin/env python

import codecs
import re

fin = codecs.open('UK.txt', 'r', 'utf_8')
b = {}

if __name__ == "__main__":
  for line in fin:
    if re.search("^\}\}$",line):
      break
    elif re.search("^\|",line):
      line = re.sub("^\|","",line)
      l = re.split("\s\=\s",line)
      l[1] = l[1].replace('\n','')
      b[l[0]] = l[1]
  print(b)

 基礎情報の終わりを"}}"だけの行と見て判別している。

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

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

#!/usr/bin/env python

import codecs
import re

fin = codecs.open('UK.txt', 'r', 'utf_8')
b = {}

if __name__ == "__main__":
  for line in fin:
    if re.search("^\}\}$",line):
      break
    elif re.search("^\|",line):
      line = re.sub("^\|","",line)
      l = re.split("\s\=\s",line)
      l[1] = l[1].replace('\n','')
      l[1] = l[1].replace('\'','')
      b[l[0]] = l[1]
  print(b)

 手抜き。本来は23のようなコードを入れるべき。

27. 内部リンクの除去

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

#!/usr/bin/env python

import codecs
import re

fin = codecs.open('UK.txt', 'r', 'utf_8')
b = {}

if __name__ == "__main__":
  for line in fin:
    if re.search("^\}\}$",line):
      break
    elif re.search("^\|",line):
      line = re.sub("^\|","",line)
      l = re.split("\s\=\s",line)
      l[1] = l[1].replace('\n','')
#強調除去部分(手抜き)
      l[1] = l[1].replace('\'','')
#内部リンクマークアップ除去部分
      l[1] = re.sub("\[\[","",l[1])
      l[1] = re.sub("\]\]","",l[1])
      b[l[0]] = l[1]
  print(b)
28. MediaWikiマークアップの除去

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

 何を削除するかが問われる。今回はhttpとファイルを削除した。
 MediaWikiマークアップではないので除去しなかったがこうなってくるとrefタグが悪目立ちしてくる。

#!/usr/bin/env python

import codecs
import json
import re

fin = codecs.open('UK.txt', 'r', 'utf_8')
b = {}

if __name__ == "__main__":
  for line in fin:
    if re.search("^\}\}$",line):
      break
    elif re.search("^\|",line):
      line = re.sub("^\|","",line)
      l = re.split("\s\=\s",line)
#強調除去部分(手抜き)
      l[1] = l[1].replace('\'','')
#マークアップ除去部分
      l[1] = re.sub("\[\[","",l[1])
      l[1] = re.sub("\]\]","",l[1])
#http削除部分
      l[1] = re.sub("\[http.*\]","",l[1])
#ファイル削除部分
      if re.search("ファイル:",line):
        l[1] = re.sub('ファイル:','',l[1])
        ll = re.split("\|",l[1])
        l[1] = ll[0]
      l[1] = l[1].replace('\n','')
      b[l[0]] = l[1]
  print(b)
29. 国旗画像のURLを取得する

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

 pythonでurlを扱うライブラリは何を使うか悩む。今回はオーソドックスにpyhton3のurllibを使用。
 ファイル名に空白が入っていると返事が帰って来ないので urllib.parse.quote_plus で処理。
 返事をjsonで要求したがなかなかうまくjsonに格納できない。諦めて literal_eval を適用して辞書型で格納。

#!/usr/bin/env python

import codecs
import re
import urllib.request
import urllib.parse
from ast import literal_eval

fin = codecs.open('UK.txt', 'r', 'utf_8')
b = {}

if __name__ == "__main__":
  for line in fin:
    if re.search("^\}\}$",line):
      break
    elif re.search("^\|",line):
      line = re.sub("^\|","",line)
      l = re.split("\s\=\s",line)
      l[1] = l[1].replace('\'','')
      l[1] = re.sub("\[\[","",l[1])
      l[1] = re.sub("\]\]","",l[1])
      l[1] = re.sub("\[http.*\]","",l[1])
      if re.search("ファイル:",line):
        l[1] = re.sub('ファイル:','',l[1])
        ll = re.split("\|",l[1])
        l[1] = ll[0]
      l[1] = l[1].replace('\n','')
      b[l[0]] = l[1]
#追加ここから
  image = urllib.parse.quote_plus(b["国旗画像"])
  src = "https://commons.wikimedia.org/w/api.php?format=json&action=query&titles=File:" + image + "&prop=imageinfo&&iiprop=url"
  response = urllib.request.urlopen(src)
  html = response.read()
  data = literal_eval(html.decode('utf-8'))
  print(data["query"]["pages"]["347935"]["imageinfo"][0]["url"])

結果

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