2015-01-08 3 views
0

Мне нужно преобразовать ByteString в список из 7 бит байтов. Например, байты с A, B, C, D и т.д. битов:Преобразование байтовой строки в список из 7 бит байтов

abcdefgh ijklmnop qrstuvwx yz... 

должны быть преобразованы в:

abcdefg hijklmn opqrstu vwxyz... 

Я использую пакет двоичных бита для того, чтобы сделать это. Моя функция convert8to7 является рекурсивной, но двоичные биты не предоставляют никакого значения для проверки отсутствия бит, тогда как монада Get имеет isEmpty или remaining.

Вот мой код:

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 

Могу ли я сделать это преобразование с двоичными битами, или я должен искать другой пакет?

Update

Вот мой код, основанный на 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

Версия Binary-Bits для взлома очень устарела. С 1 апреля 2003 года у Github был 'isEmpty :: BitGet Bool'. –

+0

Хотя он устарел, я буду придерживаться версии, предоставляемой хакером. Во-первых, это будет легче поддерживать, во-вторых, функция '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 

Update: Вот способ обнаружения конца ввода в Get монады (на вершине которого осуществляется BitGet монада). Он полагается на альтернативный класс для Get. Функция 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

Смежные вопросы