我是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 = ???????
答案 0 :(得分: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
我们可以更进一步清理这个解析器,如果您感兴趣的话,也可以更简洁:
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 "\";"
如果empty
失败,来自Control.Alternative
的 read
会失败解析器。
答案 1 :(得分:5)
我会使用Control.Monad中的replicateM
来编写它:
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"