本想自力更生试着用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