2015-01-08 55 views
0

我必须将ByteString转换为7位字节的列表。例如,字节与A,B,C,d等位:将字节串转换为7位字节列表

abcdefgh ijklmnop qrstuvwx yz... 

应转换为:

abcdefg hijklmn opqrstu vwxyz... 

我使用二进制位包,以便做到这一点。我的convert8to7功能是递归的,但二进制位没有提供任何意义来检查缺少位,而Get monad确实具有isEmptyremaining函数。

这里是我的代码:

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 

我能做到这一点,转换与二进制位或我应该找一个其他的包?

更新

这里是基于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

hackage上的Binary-Bits版本已过时。 Github上的那个自2003年4月1日以来已经有了'isEmpty :: BitGet Bool'。 –

+0

虽然已经过时了,但我会坚持使用hackage提供的版本。首先它会更容易维护,其次'isEmpty'函数不允许我处理没有足够的位形成7位字节的情况。谢谢 – zigazou

+0

不够公平。没有任何关于'BitGet'的结构可以防止添加一个完全符合你想要的功能,但是它再次不会受到黑客攻击。看到一个过时的软件包让我不禁想知道:他们是否有接管废弃项目的程序? –

回答

2

的问题是,你需要不断的比特解码的数量的轨道 - 的BitGet单子不知道当达到输入的结束时。

尝试这种情况:

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单子(在其顶部的BitGet单子被实现)输入的结束的方式。它依靠Get的Alternative类。函数chunks7将一个字节字符串分解为7个块,其余部分进入最后一个块。

据我所知,BitGet没有实现替代类 - 虽然我敢肯定它可以。

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 
+0

谢谢!这其实很简单,但我无法得到它--D – zigazou