言語処理100本ノックをやってみる 第３章：正規表現


[言語処理100本ノックをやってみる 第１章：準備運動](http://qiita.com/modal_soul/items/0578b368cf332787e61b) の続き。
言語処理100本ノックの[第2章: UNIXコマンドの基礎](http://www.cl.ecei.tohoku.ac.jp/nlp100/#ch2)は、プログラミングの問題ではないので、飛ばして第３章をやります。

今回はScalaに頼らず全問Rubyで書いた。(Rubyの正規表現って便利ですね)

前回に引き続き、Rubyだと一般的にこう書く、とか、こう書いた方が良い、とかコメントもらえると大変ありがたいです。

**注意**
*※ この回答が間違ってる可能性が有ります。*
*※ 言語処理の知識が無いので、そもそも問題文の解釈を間違えている可能性も有ります。*


## 準備
Wikipediaの記事を以下のフォーマットで書き出したファイル[jawiki-country.json.gz](http://www.cl.ecei.tohoku.ac.jp/nlp100/data/jawiki-country.json.gz)がある．

1行に1記事の情報がJSON形式で格納される
各行には記事名が"title"キーに，記事本文が"text"キーの辞書オブジェクトに格納され，そのオブジェクトがJSON形式で書き出される
ファイル全体はgzipで圧縮される
以下の処理を行うプログラムを作成せよ．

*※ 上記jawiki-country.jsonは、* **１行毎にjson** *になっていることに注意*
*ファイルをまとめてパースするとエラーになります。ハマった。。*

```ruby
require 'json'

def getParsed
    file_path="./jawiki-country.json"
    i = 0
    parsed = []
    open(file_path) do |f|
        f.each_line do |line|
            parsed.push(JSON.parse(line))
        end
    end
    parsed
end
```

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

```ruby
getParsed.select {|item| item["title"].scan(/イギリス/) != [] }.each{|item| puts item["text"]}
```

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

```ruby
uk = getParsed.select {|item| item["title"].scan(/イギリス/) != [] }[0]

uk["text"].scan(/\[\[Category:.+?\]\].*?/)
```


## 22. カテゴリ名の抽出
記事のカテゴリ名を（行単位ではなく名前で）抽出せよ．

```ruby
uk["text"].scan(/(\[\[Category:)(.+?)(\|.*?)*(\]\].*?)/).map{|c| c[1] }
```

## 23. セクション構造
記事中に含まれるセクション名とそのレベル（例えば"== セクション名 =="なら1）を表示せよ．

```ruby
uk["text"].scan(/(^=+)(\s*)(.*?)(\s*)(=+)/).map{|s| [s[2], s[0].length - 1]}.each{ |nl| puts "#{nl[0]}:#{nl[1]}"}
```

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

```ruby
uk["text"].scan(/(\[\[)(ファイル:)(.*?)(\|)(.*?)(\|)(.*?)(\]\])/).map{|i| i[2]}
```

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

```ruby
basic = uk["text"].scan(/(({{基礎情報.*\n)(|.*?\n)*(}}))/)[0][0].scan(/(\|)(.*?)(=)(.*?)(\n)/).map{|i| [i[1].strip, i[3].strip]}.to_h
```

## 26. 強調マークアップの除去
25の処理時に，テンプレートの値からMediaWikiの強調マークアップ（弱い強調，強調，強い強調のすべて）を除去してテキストに変換せよ（参考: [マークアップ早見表](http://ja.wikipedia.org/wiki/Help:%E6%97%A9%E8%A6%8B%E8%A1%A8)）．

```ruby
no_bold = basic.map{|k, v| [k, v.gsub(/(''''')(.*?)(''''')/){$2}.gsub(/(''')(.*?)(''')/){$2}.gsub(/('')(.*?)('')/){$2}] }.to_h
```


## 27. 内部リンクの除去
26の処理に加えて，テンプレートの値からMediaWikiの内部リンクマークアップを除去し，テキストに変換せよ（参考: [マークアップ早見表](http://ja.wikipedia.org/wiki/Help:%E6%97%A9%E8%A6%8B%E8%A1%A8)）．

```ruby
no_inner_link = no_bold.map{|k,v| [k, v.gsub(/(.*?)(\[\[)([^\]]*?)(\|)(.*?)(\]\])([^\[]*)/){|i|"#{$1}#{$5}#{$7}"}.gsub(/(.*?)(\[\[)([^\]]*?)(\]\])([^\[]*)/){|i|"#{$1}#{$3}#{$5}"}]}.to_h
```

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

**外部リンクの除去**

```ruby
no_outer_link = no_inner_link.map{|k,v| [k, v.gsub(/(.*?)(\[)(http[s]*:\/\/[^\s\]]*)([^\]]*?)(\])(.*?)/){|i| if $4 == '' then "#{$1}#{$3}#{$6}" else "#{$1}#{$4}#{$6}" end}]}
```

## 29. 国旗画像のURLを取得する
テンプレートの内容を利用し，国旗画像のURLを取得せよ．（ヒント: [MediaWiki API](http://www.mediawiki.org/wiki/API:Main_page/ja)の[imageinfo](http://www.mediawiki.org/wiki/API:Properties/ja#imageinfo_.2F_ii)を呼び出して，ファイル参照をURLに変換すればよい）

```ruby
require 'net/http'
require 'uri'

uri = URI.parse(URI.escape("http://www.mediawiki.org/w/api.php?action=query&format=json&titles=Image:#{no_inner_link["国旗画像"]}&prop=imageinfo&iiprop=url"))

JSON.parse(Net::HTTP.get(uri))['query']['pages']['-1']['imageinfo'][0]['url']
```