2

我编写了以下Parsec代码来解码表示Word8(无符号 8 位整数)的文本:

decOctetP = try e <|> try d <|> try c <|> try b <|> a
    where
        a = fmap (:[]) digit
        b = do
            m <- oneOf "123456789"
            n <- digit
            return [m, n]
        c = do
            char '1'
            m <- count 2 digit
            return ('1':m)
        d = do
            char '2'
            m <- oneOf "01234"
            n <- digit
            return ['2', m, n]
        e = do
            string "25"
            m <- oneOf "012345"
            return ['2', '5', m]

我不禁觉得有一种更简单的方法可以做到这一点。有人可以启发我吗?

4

3 回答 3

7

老实说,最简单的方法就是将其解析为自然数,然后通过返回 mzero 来解析超出 0-255 的范围。

import Control.Monad

import Text.Parsec
import Text.Parsec.String (Parser)
import qualified Text.Parsec.Token as Tok

natural :: Parser Integer
natural = Tok.natural lexer

number :: Parser Integer
number = do
  n <- natural
  if n < 256 then return n
  else mzero
于 2013-11-04T18:09:56.893 回答
1

最终得到了这个我认为干净直观的版本:

decOctetP = choice [e, d, c, b, a]
    where
        a = fmap (:[]) digit
        b = sequence [oneOf "123456789", digit]
        c = sequence [char '1', digit, digit]
        d = sequence [char '2', oneOf "01234", digit]
        e = sequence [char '2', char '5', oneOf "012345"]
于 2013-11-05T17:20:40.533 回答
1

您可以替换c,de使用以下内容:

decOctetP = try c <|> try b <|> a
where
    a = fmap (:[]) digit
    b = do
        m <- oneOf "123456789"
        n <- digit
        return [m, n]
    c = do
        m <- (:) <$> oneOf "123456789" <*> count 2 digit
        guard $ combine m <= 255
        return m
    combine = foldl' (\r d -> 10 * r + (ord d - ord '0')) 0

仍然不是很漂亮,但它有点短。

于 2013-11-04T18:11:01.620 回答