好吧,我需要解析十六进制的 n 位数字,但我遇到了一个问题,我无法停止标准 attoparsec 十六进制解析器十六进制
。
我的第一个想法是:
nHex n = take n *> 十六进制
但这不起作用,因为它会去掉 4 位数字,然后解析字符串 xD 的其余部分
下一个可行的想法是:
hex :: (Num a, Eq a) => Int -> Parser a
hex n = fst . head . readHex <$> count n (satisfy isHexDigit)
但是该代码的问题在于 attoparsec 库中,它警告不要返回字符列表以考虑速度问题,而这个十六进制解析器是我整个程序的基础
尝试提高速度的下一个想法是:
parseFragments :: (Bits a, Integral a) => Int -> Parser a
parseFragments n = do
fourChars <- B.take n
let hexDigits = parseOnly hexadecimal fourChars
case hexDigits of
Left err -> fail err
Right x -> return x
但这感觉像是使用 parseOnly 的可怕黑客。 有没有更快速、更惯用的方法?
最佳答案
Data.Attoparsec.ByteString.Char8.hexadecimal
是 implemented as :
hexadecimal :: (Integral a, Bits a) => Parser a
hexadecimal = B8.foldl' step 0 `fmap` I.takeWhile1 isHexDigit
where
isHexDigit w = (w >= 48 && w <= 57) ||
(w >= 97 && w <= 102) ||
(w >= 65 && w <= 70)
step a w | w >= 48 && w <= 57 = (a `shiftL` 4) .|. fromIntegral (w - 48)
| w >= 97 = (a `shiftL` 4) .|. fromIntegral (w - 87)
| otherwise = (a `shiftL` 4) .|. fromIntegral (w - 55)
您可以使用几乎相同的方法,只是您需要检查 take
的结果,因为某些字符可能不是有效的十六进制字符。您可以使用 (Maybe a -> Word8 -> Maybe a)
将两者放在同一个函数中,但为了简单起见,我使用了上面的函数:
fixedHexadecimal :: (Integral a, Bits a) => Int -> Parser a
fixedHexadecimal n = do
bytes <- A.take n
if B8.all isHexDigit bytes
then B8.foldl' step 0 bytes
else fail "fixedHexadecimal"
where isHexDigit = -- see above
step = -- see above
关于haskell - 使用 attoparsec 解析 n 个十六进制数字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29811022/