この記事は Nim Advent Calendar 2016 24 日目の記事です。
クリスマスとか年末に絡めた何かを考えていたのですが、思いつかなかったので普通に書きます。
PEG とは
PEG について、解説的なものを入れようかと思ったのですが、
Wikipedia がとても詳しく、私が生半可な知識で書くのも良くないのでそちらをご覧ください。
https://ja.wikipedia.org/wiki/Parsing_Expression_Grammar
使ってみる
使い方は PEG に慣れていればなんの抵抗もないはずですが、
私のように正規表現しか書いたことのない人間には馴染みの薄い物です。
では先日使用した json をそのまま流用して試してみます。
使用した json は json.org の JSON Example の一番上のやつです。
http://json.org/example.html
この json を example.json として保存し、使用しています。
"SortAs": "SGML",
json からkey, value (この場合は SortAs:SGML )を得たい場合
PEG ではこのように書くことができます
'"' {( \w )+} '":' \s+ '"' {( \w )+} '"' ','?
"Abbrev": "ISO 8879:1986",
この場合は
'"' {( \w )+} '":' \s+ '"' {( \w / \s / ':' )+} '"' ','?
となります。
これらの規則は非終端記号として定義できます。
grammer <- '"' {( \w )+} '":' \s+ '"' {( \w / \s / ':' )+} '"' ','?
key, value 部分をまとめて以下のような記述にもできます。
grammer <- '"' cap '":' \s+ '"' cap '"' ','? cap <- {( \w / \s / ':' )+}
最後に、json 全体をパースしてみます
rule <- '{' \s+ '"glossary":' \s+ '{' \s+ title '"GlossDiv":' \s+ '{' \s+ title '"GlossList":' \s+ '{' \s+ '"GlossEntry":' \s+ '{' \s+ (glossDef / pair)* glossDef <- '"GlossDef":' \s+ '{' \s+ pair '},' \s+ pair <- '"' cap '":' \s+ '"' cap '"' ','? \s+ title <- '"title":' \s+ '"' cap '",' \s+ cap <- {( \w / \s / [.,-:;] )+}
このままだと nim ではなく PEG の話になるので申し訳程度にコードと結果を載せておきます
ちなみに今回の json でしか機能せず汎用性は全くありませんので...
import pegs const peg = """ rule <- '{' \s+ '"glossary":' \s+ '{' \s+ title '"GlossDiv":' \s+ '{' \s+ title '"GlossList":' \s+ '{' \s+ '"GlossEntry":' \s+ '{' \s+ (glossDef / pair)* glossDef <- '"GlossDef":' \s+ '{' \s+ pair '},' \s+ pair <- '"' cap '":' \s+ '"' cap '"' ','? \s+ title <- '"title":' \s+ '"' cap '",' \s+ cap <- {( \w / \s / [.,-:;] )+} """ let str = "example.json".readFile() if str =~ peg(peg): for i in 0..(matches.len - 1): if i < 2: echo "title: ", matches[i] else: if matches[i] != nil: if i mod 2 == 0: echo "key: ", matches[i] else: echo "value: ", matches[i]
この出力は以下の通りです。
title: example glossary title: S key: ID value: SGML key: SortAs value: SGML key: GlossTerm value: Standard Generalized Markup Language key: Acronym value: SGML key: Abbrev value: ISO 8879:1986 key: para value: A meta-markup language, used to create markup languages such as DocBook. key: GlossSee value: markup