将字节字符串转换为7位字节的列表

时间:2015-01-08 05:52:50

标签: haskell

我必须将ByteString转换为7位字节的列表。例如,带有a,b,c,d等位的字节:

abcdefgh ijklmnop qrstuvwx yz...

应转换为:

abcdefg hijklmn opqrstu vwxyz...

我使用Binary-Bits包来执行此操作。我的convert8to7函数是递归的,但是Binary-Bits没有提供检查缺少位的任何方法,而Get monad确实具有isEmptyremaining函数。 / 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

1 个答案:

答案 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