0

I'm trying to write a parser for a JSON String.

A valid example, per my parser, would be: "\"foobar\"" or "\"foo\"bar\"".

Here's what I attempted, but it does not terminate:

parseEscapedQuotes :: Parser String
parseEscapedQuotes = Parser f
  where
    f ('"':xs) = Just ("\"", xs)
    f _        = Nothing

parseStringJValue :: Parser JValue
parseStringJValue = (\x -> S (concat x)) <$> 
         ((char '"') *> 
         (zeroOrMore (alt parseEscapedQuotes (oneOrMore (notChar '"')))) 
         <* (char '"'))

My reasoning is that, I can have a repetition of either escaped quotes "\"" or characters not equal to ".

But it's not working as I expected:

ghci> runParser parseStringJValue "\"foobar\""
Nothing
3
  • Provide an SSCCE please. Commented Feb 18, 2015 at 4:00
  • What is (zeroOrMore (alt parseEscapedQuotes (oneOrMore (notChar '"')))) supposed to do? What is alt? Why not just zeroOrMore (notChar '"')? Commented Feb 18, 2015 at 4:54
  • Because I want to handle escaped quotes, @user2407038. Commented Feb 18, 2015 at 15:18

1 Answer 1

1

I don't know what parser combinator library you are using, but here is a working example using Parsec. I'm using monadic style to make it clearer what's going on, but it is easily translated to applicative style.

import Text.Parsec
import Text.Parsec.String

jchar :: Parser Char
jchar = escaped <|> anyChar

escaped :: Parser Char
escaped = do
  char '\\'
  c <- oneOf ['"', '\\', 'r', 't' ] -- etc.
  return $ case c of
            'r' -> '\r'
            't' -> '\t'
            _   -> c

jstringLiteral :: Parser String
jstringLiteral = do
  char '"'
  cs <- manyTill jchar (char '"') 
  return cs

test1 = parse jstringLiteral "" "\"This is a test\""
test2 = parse jstringLiteral "" "\"This is an embedded quote: \\\" after quote\""
test3 = parse jstringLiteral "" "\"Embedded return: \\r\""

Note the extra level of backslashes needed to represent parser input as Haskell string literals. Reading the input from a file would make creating the parser input more convenient.

The definition of the manyTill combinator is:

manyTill p end      = scan
  where
    scan  = do{ end; return [] }
            <|>
            do{ x <- p; xs <- scan; return (x:xs) }

and this might help you figure out why your definitions aren't working.

Sign up to request clarification or add additional context in comments.

4 Comments

What's the meaning of char '\\' in escaped? PS - It's a custom parser library that I'm working on.
also, my initial problem was that zeroOrMore has type Parser a -> Parser [a]. I was trying to call <|> (zeroOrMore (notQuote)) escaped, but it was not working as expected: runParser parseStringJValue "\"fo\"obar\"" === Just (S "fo","obar\"")
The char function recognizes a single charater, e.g. char 'x' recognizes the character 'x'. The character literal '\\' is how you represent the backslash character.
So an escaped character sequence is a backslash character followed by a double-quote, backslash, the letter 'r' or the letter 't' - and that's what the escaped parser recognizes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.