本想自力更生试着用Haskell写个
JSON解析器,一不小心网上一搜一大把,并且忍不住瞄了几眼。那就做个简单的修改加翻译吧,原文
链接:http://snippets.dzone.com/posts/show/3660
> import Text.ParserCombinators.Parsec
> import System
> import qualified Data.Map as Map引入一些必要的库,比如Parsec,祭起我们的利器哈!
> mainParser = do {
>               val <- valueParser
>             ; skipMany space
>             ; eof
>             ; return val
>             }解析器的主函数,该函数以典型的Monad风格对输入数据调用valueParser函数进行解析,do中的操作是序列华的,每一个行都是一次匹配,这三行的意思是,它期待的输入的格式是JSON数据、可能的一些空字符、文件尾巴,如果解析成功就返回解析后的数据val。
> main :: IO ()
> main = do {
>         args <- getArgs
>       ; val <- parseFromFile mainParser $ args !! 0
>       ; print val
>       }main函数先得到命令行参数存在列表args中,列表的第一个元素(args !! 0)作为文件名,parserFromFile是Parsec里的一个函数,它调用mainParser对命令行指定的文件进行解析,最后在打印出解析结果val。
> data JSON = ListValue [JSON]
>                    | LiteralString String
>                    | LiteralInt Integer
>                    | LiteralBoolean Bool
>                    | RecordValue (Map.Map String JSON)
>                        deriving Show
上面的这些玩意儿叫做
ADT,它的意思是:我们有JSON这样一种数据结构,它有五个构造函数ListValue, LiteralString, LiteralInt, LiteralBoolean和RecordValue,每个构造函数后面跟着的都是一种类型。最后,该数据结构继承所有Show类具有的行为 -- 这使得JSON类型的数据可以用print显示出来。
有了上面的定义后,我们可以方便的构造出一些JSON类型的数据,比如:
LiteralString "abc"
LiteralInt 123在GHC或者Hugs中可以用:t来显示给定输入的类型:
:t LiteralString "abc"
LiteralString "abc" :: JSON这是说LiteralString "abc"是个JSON类型。好了,接下来写几个简单的parser,我们可以dive & conquer。第一个Parser用来识别字符串 -- 字符串以'"'开头,中间是一个或者多个字符,最后有个'"'收尾。解析成功后会返回一个JSON类型的字符串。
> literalString :: Parser JSON
> literalString = do {
>     char '"'
>                    ; val <-  many1 letter
>                    ; char '"'
>                    ; return $ LiteralString val
>                    }接下来雷同的便是解析整型、布尔型:
> literalInt :: Parser JSON
> literalInt = do {
>                 ; val <- many1 digit
>                 ; return $ LiteralInt (read val)
>                 }>
> literalBoolean :: Parser JSON
> literalBoolean =
>                        do {
>                            string "true"
>                        ; return $ LiteralBoolean True
>                        }
>                <|> do {
>                          string "false"
>                        ; return $ LiteralBoolean False
>                        }
这里'<|>'是个combinator,它用来连接两个parser,如果前一个解析不成功,就用下一个来解析。用'<|>'可以把整个JSON的解析写成如下形式:
> valueParser :: Parser JSON
> valueParser =
>        literalString
>     <|> literalInt
>     <|> literalBoolean
>     <|> recordParser
>     <|> listParser其中还有两个parser没有实现:recordParser和listParser,分别用来解析object和array。list以'['打头,']'结尾,其中的数据以','分割:
> listParser :: Parser JSON
> listParser = do {
>                   char '['
>                 ; words <- sepBy1 valueParser listSeparator
>                 ; char ']'
>                 ; return $ ListValue words
>                 }>
> listSeparator :: Parser ()
> listSeparator = do {
>                      skipMany space
>                    ; char ','
>                    ; skipMany space
>                    }
最后就是解析object啦,打完收功!
> recordParser :: Parser JSON
> recordParser = do {
>                      char '{'
>                    ; defs <- endBy definitionParser listSeparator
>                    ; char '}'
>                    ; return $ RecordValue $ Map.fromList defs
>                    }>
> definitionParser :: Parser (String, JSON)
> definitionParser = do {
>                          skipMany space
>                        ; key <- many1 letter
>                        ; char ':'
>                        ; skipMany space
>                        ; val <- valueParser
>                        ; return (key, val)
>                        }
>
> definitionSeparator :: Parser ()
> definitionSeparator = do {
>                             skipMany space
>                           ; char ','
>                           ; skipMany space
>                           ; return ()
>                           }
标签: haskell