人気ブログランキング | 話題のタグを見る

Parsec パーサコンビネータ many, many1

パーサコンビネータとは、パーサ(関数)を引数に取る高階関数のことで、パーサを組み合わせて新しいパーサを組み立てることができる。正規表現の * や + と同じ作用をするのが、many と many1 というパーサコンビネータだ。

many は引き数のパーサを0回以上くりかえすパターンにマッチする。例えば letter は英文字1字にマッチするので、many letter は "hello world" のスペースが出現するまでの部分にマッチする。

Prelude> parseTest (many letter) "hello world"
"hello"

このような使い方の時は many1 でも動作は同じだ。

Prelude> parseTest (many1 letter) "hello world"
"hello"

しかし、最初からひとつも英文字がない次のような場合は、many はマッチするが、many1 まマッチ・エラーになる。

Prelude Text.ParserCombinators.Parsec> parseTest (many1 letter) "123"
parse error at (line 1, column 1):
unexpected "1"
expecting letter

skipMany, skipMany1 は many, many1 と同じマッチをするが、結果は捨てさってしまう。

Prelude> parseTest (skipMany letter) "hello world"
()

sepBy, sepBy1 は、引き数に取り出したいデータのパーサとセパレターにマッチするパーサをとり、セパレータでデータを分割してリストにして戻す。ややこしいが、トライアンドエラーで何回か使ってみると、そのありがたさが分かる。

Prelude> parseTest (sepBy (many letter) (char ',')) "apple,banana,orange"
["apple","banana","orange"]

endBy, endBy1 は sepBy と同じやり方で終端記号で行を分割する。

Prelude> parseTest (endBy (many letter) (char ';')) "hello;world;"
["hello","world"]

sepEndBy, sepEndBy1 は sepBy と sepEnd を組み合わせたような動作をする。

Prelude> parseTest (sepEndBy (many letter) (oneOf ",;")) "hello,world;how,are,you"
["hello","world","how","are","you"]

count は引き数に個数とパーサをとり、そのパーサにマッチを回数指定でマッチする。

Prelude> parseTest (count 3 (string "hello")) "hellohellohellohellohello"
["hello","hello","hello"]

between は記号や文字列で挟まれた部分とマッチする。

Prelude> parseTest (between (char '{') (char '}') (many letter)) "{hello} world"
"hello"

option は第2引数のパターンマッチが失敗した時、第1引き数の値を返す。パターンマッチが成功すればその値が戻される。

Prelude> parseTest (option "universe" (string "world")) "hello world"
"universe"
Prelude> parseTest (option "universe" (string "hello")) "hello world"
"hello"

choice はリストにしたパターンのどれかにマッチすればその値を戻す。

Prelud> parseTest (choice [many1 letter, many1 digit]) "123 hello"
"123"

manyTill p end はend のパターンが現れるまでの部分を取り出す。

Prelude> parseTest (manyTill anyChar (char ';')) "hello world; nice to meet you"
"hello world"

chainl, chainl1 は、左結合の演算のパーサを作るときに便利な関数だが面倒なのでメモだけ。

chainr, chainr1 は、右結合の演算のパーサを作るときに使う。これもメモだけ

eof はファイルの終わりを判別する。

Prelude> parseTest eof ""
()
Prelude> parseTest eof "a"
parse error at (line 1, column 1):
unexpected "a"
expecting end of input

notFollowedBy は、最長マッチを実現するためにつかうパーサ。これもメモのみ

anyToken パースするトークンが残っているかどうかの検査。これもメモのみ。
by tnomura9 | 2011-11-27 17:59 | Haskell | Comments(0)
<< Parsec 連接と選択 Parsec parseTes... >>