LoginSignup
6
6

More than 5 years have passed since last update.

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

Posted at

言語処理100本ノックをやってみる 第1章:準備運動 の続き。
言語処理100本ノックの第2章: UNIXコマンドの基礎は、プログラミングの問題ではないので、飛ばして第3章をやります。

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

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

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

準備

Wikipediaの記事を以下のフォーマットで書き出したファイルjawiki-country.json.gzがある.

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

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

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では,ここで抽出した記事本文に対して実行せよ.

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

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

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

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

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

22. カテゴリ名の抽出

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

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

23. セクション構造

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

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

24. ファイル参照の抽出

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

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

25. テンプレートの抽出

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

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

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

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

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

27. 内部リンクの除去

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

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マークアップを可能な限り除去し,国の基本情報を整形せよ.

外部リンクの除去

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 APIimageinfoを呼び出して,ファイル参照をURLに変換すればよい)

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']
6
6
7

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
6
6