"Write Yourself a Scheme in 48 Hours/Parsing" http://en.wikibooks.org/wiki/Write_Yourself_a_Scheme_in_48_Hours/Parsing を読む
Parsingの練習問題の続き。
Excercise 2 support escaping of internal quotes (続き)
many (noneOf "\"")
の部分は、このままだと、「"」が来たら止まって、それまで読んだところを文字列で返すような感じになっている。
で、「abc"def"g」 だったら、(「abc」 , 「"def"g」)だけど、
「abc\"def"g」 だったら(「abc"def」 , 「"g」) という感じにしたいと。つまりバックスラッシュでのエスケープに対応したい。
(noneOf "\"")のところだけ変えてもどうにもうまくいきそうにない感じなので、manyの部分を展開することに。で、前回はmanyと
同じように動かすにはどうすればいいか考えた、と。で今回はそれをもとに、many (noneOf "\"")とほぼ同じように動くだろうと思われるものを、manyを使わずに書いてみた。
pstr = do { x <- noneOf "\""; do { xs <- pstr; return (x:xs) } <|> return [x] } <|> return []
どうやったらもっときれいに書けるのか?今は期待通り動けばよしとして先に行く。
で、これにエスケープの仕組みを加えるために、とりあえず、「\"」ときたら「"」と読むパーサを作る。
escaped = do { _ <- char '\\'; x <- char '\"'; return [x] }
もっときれいに書けないだろうか。
escaped2 = liftM (:[]) $char '\\' >> char '\"'
最初のdo記法のままで十分な気がした。試しに動かしてみる。
Main> let p (Right x) = putStr (x++"\n");p x = print x Main> p$parse escaped "" "" Left (line 1, column 1): unexpected end of input expecting "\\" Main> p$parse escaped "" "\\" Left (line 1, column 2): unexpected end of input expecting "\"" Main> p$parse escaped "" "\\\"" " Main> p$parse escaped "" "\\\"a" "
OKでしょう。ではこれでさっきのpstr にescapedを加えてみる。
pstr = do { x <- noneOf "\""; do { xs <- pstr; return (x:xs) } <|> return [x] } <|> do { xs <- escaped; ys <- pstr; return (xs ++ ys) } <|> return []
動きを確かめてみると、
Main> p$parse pstrold "" "abc\"" abc Main> p$parse pstrold "" "abc\\\"" abc\ Main> p$parse pstrold "" "abc\\\"e" abc\
だめでした。
pstr = do { xs <- escaped; ys <- pstr; return (xs ++ ys) } <|> do { x <- noneOf "\""; do { xs <- pstr; return (x:xs) } <|> return [x] } <|> return []
順番を変えてみると、
Main> p$parse pstr "" "abc\\\"e" abc"e
うまくいったもよう。