7

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

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 = ???????
4

2 回答 2

9

正如莎拉所提到的,惯用的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

如果您对此感兴趣,我们可以更进一步并清理这个解析器以使其更简洁:

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

或者甚至:

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

emptyfromControl.Alternative使解析器失败,以防read失败。

于 2013-03-18T11:39:56.880 回答
6

我会使用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

在 ghci 中测试它:

*Main> parse pString "" "s:12:\"123\";6789012\";"
Right "123\";6789012"
于 2013-03-18T10:44:51.060 回答