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

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 "\";"

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 に答える