なんとな~くしあわせ?の日記

「そしてそれゆえ、知識そのものが力である」 (Nam et ipsa scientia potestas est.) 〜 フランシス・ベーコン

Instaparseでパーサジェネレータ

Instaparseの位置づけ

InstaparseはClojure言語による パーサジェネレータ - Wikipedia である

github.com

これのルール記述はBNFの拡張であるEBNFが使われている。

EBNFで構造化言語のルールを記述する

さっそくだが、「<p>sample</p>」を読み取るBNFのルールを書いてみた。とは言え、HTMLの複雑なルールを最初から書くのは無理なので、とりあえずタグの開始と終了を読み取れるものを作る。

しかもこのルール記述、de.setf.xml/html-grammar.bnf at master · lisp/de.setf.xml · GitHub からコピーしてきたものである。

コードサンプル
(ns sample
  (:require [instaparse.core :as insta]))

;;
;; https://github.com/lisp/de.setf.xml/blob/master/bnf/html-grammar.bnf
;;
(def as-and-bs
  (insta/parser
   "HtmlDocument ::= Root
    Root         ::= ElementHtml
    ElementHtml  ::= HtmlTag | ( STag ( '/>' | ( '>' #'\\w'++ ETag ) ) )
    HtmlTag      ::= '<'  #'\\w'++ S* '>'
    STag         ::= '<'  #'\\w'++ S*
    ETag         ::= '</' #'\\w'++ S* '>'

    S ::= (' ' | '\t' | '\r\n' | '\n')+
"))

(def fool-tags "<p>sample</p>")

(defn fool-sample []
  (println (as-and-bs fool-tags)))
出力
  • sampleのデータがきっちり構造化されて戻ってきた
lein test html-template.test
[:HtmlDocument [:Root [:ElementHtml [:STag < p] > s a m p l e [:ETag </ p >]]]]

後はこれに対して指定されたキーを使ってデータを取得したりすればいいのである。

パーサジェネレータについて調べた

パーサジェネレータの位置づけ

少しだけパーサジェネレータについて書く。パーサジェネレータとはパーサを生成できるソフトウェアのことである。

そもそもパーサとはなんだったか確認しよう。

パーサ(=構文解析器)

パーサとは 構文解析器 - Wikipedia である。

XMLを読み取るパーサの例としては Document Object Model - WikipediaSimple API for XML - Wikipedia。要はDOMやSaxである。Javaを書いたことがあればちょっとは使ったことがあるはず。最近はXMLからJavaに変換する時は Java Architecture for XML Binding - Wikipedia を使うかもしれない。

構造を持った入力テキストの処理をおこなうものはすべてパーサだと言える。

なぜテキストに構造を持たせなければいけないのか?それは データ記述言語 - Wikipedia に書かれている以下のような理由による:

データ記述言語は、以下の点に主眼を置いて作られた。
  1.複雑なデータ構造をもつデータを格納する。
  2.データの記述方法や個々のデータ要素へのアクセス方法の共通化をはかる。
  3.データをテキスト形式で格納する。

ただのテキストファイルだと、日付や誰によって更新されたか、どの部分が列でどの部分が行か?わからない。そういったデータの格納の仕方を定めたXML, JSON, HTML, そしてCSVやTSVすべてデータ記述言語と言える。XMLがまどろっこしいのは別にプログラマーがマゾだからではなく、付与したい情報が多いからである。

パーサジェネレータの利点

パーサがデータ記述言語によって構造化されたデータを読み取れることはわかった。では、パーサジェネレータは何ができるのか?

パーサジェネレータは、なんとこのデータ記述言語のルールを記述するだけでパーサを作ってくれる。スゴイ!

次の記事でそれを実践していく:


パーサジェネレータの実装の種類

Wikipediaを見ると、以下のような手法があるようだ

AtCoder - AtCoder Beginner Contest 012 (バスと避けられない運命) を解いてみた

前回の競プロ!

ダイクストラ法を学んでようやくスタート地点に立てました。

ダイクストラ法については以下のエントリを参照。

nantonaku-shiawase.hatenablog.com

解法

Rubyによる解答 TLE

アルゴリズムは正しそうですが11個のテストケースでTLEしてしまいました。

Submission #1725365 - AtCoder Beginner Contest 012 | AtCoder

f:id:panzer-jagdironscrap1:20171031213136p:plain

D言語による解答 AC!

しかしそんなことでは諦めない。もちろん俺らは抵抗するで?拳で*1

Submission #1728053 - AtCoder Beginner Contest 012 | AtCoder

f:id:panzer-jagdironscrap1:20171031213451p:plain