如何用Parsec读取精确的N个字符?

vio*_*ior 6 haskell parsec

我是Haskell和Parsec的新手.我希望解析字符串的php-serialize格式:numb:"string";' 喜欢

S:12: "123"; 6789012" ;

其中number是字符数.所以,功能看起来像:

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 = ???????
Run Code Online (Sandbox Code Playgroud)

och*_*les 9

正如Sarah所提到的,惯用的parsec解决方案是使用count组合器:

newtype PhpString = PhpString String

pString :: Parser PhpString
pString = do
  string "s:"
  value1 <- many1 digit
  string ":\""
  value2 <- count (read value1) 
  string "\";"      
  return $ PhpString value2
Run Code Online (Sandbox Code Playgroud)

如果您感兴趣的话,我们可以更进一步清理这个解析器,以便更简洁一些:

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
Run Code Online (Sandbox Code Playgroud)

或者甚至是:

pString :: Parser PhpString
pString =
  readMaybe <$> (string "s:" *> many1 digit) >>=
    maybe empty $ \n ->
      PhpString <$> string ":\"" *> count n anyChar <* string "\";"
Run Code Online (Sandbox Code Playgroud)

empty如果Control.Alternative失败,则解析器read失败.


Chr*_*lor 5

我会使用replicateMControl.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
Run Code Online (Sandbox Code Playgroud)

在ghci中测试它:

*Main> parse pString "" "s:12:\"123\";6789012\";"
Right "123\";6789012"
Run Code Online (Sandbox Code Playgroud)