2015-01-08 53 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