我是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)
正如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
失败.
我会使用replicateM
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
Run Code Online (Sandbox Code Playgroud)
在ghci中测试它:
*Main> parse pString "" "s:12:\"123\";6789012\";"
Right "123\";6789012"
Run Code Online (Sandbox Code Playgroud)