我必须将ByteString转换为7位字节的列表。例如,带有a,b,c,d等位的字节:
abcdefgh ijklmnop qrstuvwx yz...
应转换为:
abcdefg hijklmn opqrstu vwxyz...
我使用Binary-Bits包来执行此操作。我的convert8to7
函数是递归的,但是Binary-Bits没有提供检查缺少位的任何方法,而Get
monad确实具有isEmpty
或remaining
函数。 / p>
这是我的代码:
import Data.Word
import Data.Binary.Bits.Get
import Data.Binary.Get (runGet)
import Data.ByteString.Lazy.Char8
convert8to7 :: BitGet [Word8]
convert8to7 = do
bits <- getWord8 7
rest <- convert8to7
return (bits : rest)
main :: IO ()
main = do
let datas = pack "Hello world!"
print $ runGet (runBitGet convert8to7) datas
当我运行此代码时,它逻辑上说:
Data.Binary.Get.runGet at position 12: demandInput: not enough bytes
我可以使用Binary-Bits进行此转换,还是应该查找其他包?
更新
这是我的代码基于user5402回答:
import Data.Word
import Data.Bits
import Data.Binary.Bits.Get
import Data.Binary.Get (runGet)
import qualified Data.ByteString.Lazy.Char8 as BS
convert87 :: Int -> BitGet [Word8]
convert87 n
| n == 0 = return []
| n < 7 = do bits <- getWord8 n
return [shiftL bits (7 - n)]
| otherwise = do bits <- getWord8 7
rest <- convert87 (n-7)
return $ bits : rest
to87 :: BS.ByteString -> [Word8]
to87 datas = runGet (runBitGet (convert87 len)) datas
where len = fromIntegral $ BS.length datas * 8
main :: IO ()
main = do
let datas = BS.pack "Hello world!"
print $ to87 datas
答案 0 :(得分:2)
问题是您需要跟踪要解码的位数 - BitGet
monad不知道何时到达输入结束。
试试这个:
import Data.Word
import Data.Binary.Bits.Get
import Data.Binary.Get (runGet)
import Data.ByteString.Lazy.Char8
import qualified Data.ByteString.Lazy.Char8 as BS
convert87 :: Int -> BitGet [Word8]
convert87 n
| n < 7 = do bits <- getWord8 n
return [bits]
| otherwise = do bits <- getWord8 7
rest <- convert87 (n-7)
return $ bits : rest
main :: IO ()
main = do
let datas = pack "Hello world!"
len = fromIntegral $ BS.length datas * 8
print $ runGet (runBitGet (convert87 len)) datas
更新:这是检测Get
monad中输入结束的方法(在其上面实现了BitGet
monad)。它依赖于Get
的Alternative类。函数chunks7
将一个字节字符串分成7个块,其余的余数都会进入最后一个块。
据我所知,BitGet
没有实现Alternative类 - 虽然我确信它可以。
import Data.Word (Word8)
import Data.Binary.Get
import Data.ByteString.Lazy.Char8
import qualified Data.ByteString as BSW
import qualified Data.ByteString.Lazy as BSL
import Control.Applicative -- used for (<|>)
chunks7 :: Get [[Word8]]
chunks7 = do
b <- isEmpty
if b
then return []
else do chunk <- fmap BSW.unpack (getByteString 7)
<|> fmap BSL.unpack getRemainingLazyByteString
rest <- chunks7
return $ chunk : rest
main :: IO ()
main = do
let datas = pack "Hello world! This is a test"
print $ runGet chunks7 datas