I'm new to Haskell and Parsec. I wish to parse php-serialize format of string 's:numb:"string";' like
s:12:"123";6789012";
where number is count of chars. So, function looks like:
newtype PhpString = PhpString String
pString :: GenParser Char st PhpString
pString = do { string "s:"
; value1 <- many1 digit
; string ":\""
; value2 <- takeExactNChars (read value1)
; string "\";"
; return $ PhpString value2
}
where
takeExactNChars n = ???????
As Sarah mentioned, the idiomatic parsec
solution is to use the count
combinator:
newtype PhpString = PhpString String
pString :: Parser PhpString
pString = do
string "s:"
value1 <- many1 digit
string ":\""
value2 <- count (read value1)
string "\";"
return $ PhpString value2
We can go a bit further and clean this parser up to be a bit more succinct too, if that interests you:
import Control.Applicative (empty)
import Text.Read
pString :: Parser PhpString
pString = do
len <- readMaybe <$> (string "s:" *> many1 digit)
case len of
Just n -> PhpString <$> string ":\"" *> count n anyChar <* string "\";"
Nothing -> empty
Or perhaps even:
pString :: Parser PhpString
pString =
readMaybe <$> (string "s:" *> many1 digit) >>=
maybe empty $ \n ->
PhpString <$> string ":\"" *> count n anyChar <* string "\";"
empty
from Control.Alternative
fails the parser, in case the read
fails.
I would write it using replicateM
from Control.Monad:
import Text.ParserCombinators.Parsec
import Control.Monad (replicateM)
pString :: Parser String
pString = do string "s:"
n <- fmap read (many1 digit)
string ":\"" -- Bug fix; you weren't picking up the colon
s <- replicateM n anyChar
string "\";"
return s
Testing it in ghci:
*Main> parse pString "" "s:12:\"123\";6789012\";"
Right "123\";6789012"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With