Text.Parsec.Char
Text.Parsec モジュール
Haskell を勉強するからには Parsec も使ってみたい。Parsec を使うためには Text.Parsec モジュールをインポートする。
Prelude> import Text.Parsec Prelude Text.Parsec>
パーサ
Parsec の用語でパーサとは文字列のパターンを発見するための、プログラムの小片のことだ。実際には ParsecT s u m a 型のモナド値である。
たとえば、letter というパーサは英文字1文字にマッチするし、digit というパーサは数字1文字にマッチする。しかし、パーサを直接に文字列に関数適用することはできないので、parse 関数の第1引数としてパーサを与えることでパターンマッチが行われる。パターンを発見したい文字列は第3引数として与える。第2引数には文字列を与えるが、それはエラーメッセージのときに使われる。
Prelude Text.Parsec> parse letter "foo" "abc" Right 'a' Prelude Text.Parsec> parse digit "foo" "123" Right '1' Prelude Text.Parsec> parse digit "foo" "abc" Left "foo" (line 1, column 1): unexpected "a" expecting digit
要するに、parse 関数にパーサと文字列を渡してやれば、文字列の先頭部分のパターンマッチが行われる。簡単だ。
1文字のパーサ
1文字のパターンマッチ用のパーサは Text.Parsec.Char モジュールに定義されている。
Prelude Text.Parsec> :browse Text.Parsec.Char alphaNum :: Stream s m Char => ParsecT s u m Char anyChar :: Stream s m Char => ParsecT s u m Char char :: Stream s m Char => Char -> ParsecT s u m Char crlf :: Stream s m Char => ParsecT s u m Char digit :: Stream s m Char => ParsecT s u m Char endOfLine :: Stream s m Char => ParsecT s u m Char hexDigit :: Stream s m Char => ParsecT s u m Char letter :: Stream s m Char => ParsecT s u m Char lower :: Stream s m Char => ParsecT s u m Char newline :: Stream s m Char => ParsecT s u m Char noneOf :: Stream s m Char => [Char] -> ParsecT s u m Char octDigit :: Stream s m Char => ParsecT s u m Char oneOf :: Stream s m Char => [Char] -> ParsecT s u m Char satisfy :: Stream s m Char => (Char -> Bool) -> ParsecT s u m Char space :: Stream s m Char => ParsecT s u m Char spaces :: Stream s m Char => ParsecT s u m () string :: Stream s m Char => String -> ParsecT s u m String tab :: Stream s m Char => ParsecT s u m Char upper :: Stream s m Char => ParsecT s u m Char
各パーサがどんなパターンにマッチするのかは、名前を見ればなんとなくわかる。たとえば、anyChar はどんな文字でもひとつの文字にマッチするし、newline は改行文字にマッチする。oneOf は文字列のリストのどれかにマッチするし、noneOf は文字列のリストに含まれない文字にマッチする。
Prelude Text.Parsec> parse (oneOf "ab") "foo" "abc" Right 'a' Prelude Text.Parsec> parse (noneOf "ab") "foo" "cde" Right 'c'
パーサはモナド値なので do 記法で順次実行することもできる。
Prelude Text.Parsec> parse (do {letter; digit; letter}) "foo" "a1b" Right 'b'
また、<- 記法で変数にモナドのコンテナの値を取り出したり、それを加工したりできる。
Prelude Text.Parsec> parse (do x <- letter; y <- digit; z <- letter; return (x:y:z:[])) "foo" "a1bcde" Right "a1b"
Parsec で使用可能な 1 文字のパーサが Text.Parsec.Char を覗けば (:browse) 調べることができるし、パーサの本体はモナドで、実際のパースは parse 関数で行うということを理解すれば、Parsec活用の第1歩はクリアだ。