为JSON字符串编写解析器

时间:2015-02-16 04:56:03

标签: parsing haskell monads

作为尝试编写JSON Parser的一部分,我正在解析JSON字符串值。

根据Brent Yorgey教授的Haskell course的以下定义:

-- A parser for a value of type a is a function which takes a String
-- represnting the input to be parsed, and succeeds or fails; if it
-- succeeds, it returns the parsed value along with the remainder of
-- the input.
newtype Parser a = Parser { runParser :: String -> Maybe (a, String) }

我遇到了麻烦,因为据我所知,我的第二个解析器zeroOrMore notEndOfString只消耗每个令牌,直到到达String的末尾。

data JValue = S String | ...

parseStringJValue :: Parser JValue
parseStringJValue = S <$> ((char '"') *> (zeroOrMore notEndOfString) <* (char '"'))

notEndOfString :: Parser Char
notEndOfString = Parser f
  where 
    f []     = Nothing
    f (x:xs) = Just (x, xs)

使用这种适用方法,请给我一个提示,将我的上述parseStringJValue修改为实际工作。

注意 - 我对如何使用Monads解决它有一个微弱的想法,但我不确定它们是否是必需的。

1 个答案:

答案 0 :(得分:1)

notEndOfString匹配并消费文本中的任何字符,包括" 直到结尾,因此它贪婪地使用所有字符,从不切换到{{ 1}}解析器。您需要匹配不是引用的引号内的任何字符,这意味着您需要否定char '"'

如果您有char,那么可能是您从char构建的,这意味着您还可以定义satisfy

notChar

(顺便说一下,notChar c = satisfy (/= c) 只是notEndOfString)。否则,您可以类似于satisfy id编写它。

然后,您可以通过构建一些其他有用的组合器来定义字符串的解析器:

char

请注意,这不会在引号内处理转义(bracket l r p = l *> p <* r quotes = bracket (char '"') (char '"') parseStringJValue = S <$> quotes (zeroOrMore (notChar '"')) )。


编辑:要强制执行上面隐含的不变量,定义

会很好
"\""

然后inside l r = bracket (char l) (char r) (zeroOrMore (notChar r))