Reputation: 1141
I just started using parsec and I am trying to do something simple.
I want to separate key-value strings, as shown in this parsec tutorial.
For example, the string FirstN=Tom&LastN=Brady
should give [["FirstN","Tom"],["LastN","Brady"]]
.
This is easy, but I would also like to allow the '='
character in the string to be escaped. For example, the string Equation=1+1\\=2
should give [["Equation", "1+1\\=2"]]
(or [["Equation","1+1=2"]]
but I haven't decided which is best yet).
For the simple example the parsing code is the following:
kvParser :: String -> Either ParseError [[String]]
kvParser input = parse kvString "Error text?" input
kvString = sepBy kvVal (char '&')
kvVal = sepBy (many (noneOf "=&")) (char '=')
To allow an escaped =
I think I need to modify the (char '=')
value but I'm not sure how. Does anyone have any suggestions?
Thanks
Edit: The final working parser is
kvParser :: String -> Either ParseError [[String]]
kvParser input = parse kvString "Error text?" input
kvString = sepBy kvVal (char '&')
kvVal = sepBy (many kvChar) (char '=')
kvChar = noneOf "\\&=" <|> (char '\\' >> anyChar)
I also got the following to work using a try
combinator.
kvParser :: String -> Either ParseError [[String]]
kvParser input = parse kvString "Error text?" input
kvString = sepBy kvVal (char '&')
kvVal = sepBy (many kvChar) (char '=')
kvChar = try (string "\\=" >> return '=') <|> noneOf "&="
Upvotes: 0
Views: 486
Reputation: 62848
The separator is fine; what you want is to accept \=
as part of a key or value. Instead of
noneOf "=&"
you might try
(noneOf "\\&" <|> (char '\\' >> anyChar))
That is, noneOf
will accept anything that isn't a backslash, otherwise the parser on the right will accept (and skip) a backslash and keep the character following it. That should prevent it being detected as a separator.
Upvotes: 3