2014-02-14 68 views
1

我有一個字符串x可能或不可以gzip壓縮。使用zlib庫,我想嘗試解壓縮x - 如果成功,該函數將返回壓縮字符串。如果不是(即x不是用gzip壓縮的),我想簡單地返回x處理哈斯克爾zlib解壓縮錯誤

作爲GZip.decompress如果施加到非gzip的字符串產生一個error,我可以使用catch或相似,但我特別要求使用該zlib錯誤處理機制的溶液。

我該如何編寫一個函數,比如decompressIfPossible :: ByteString -> ByteString,它具有上述的特性?我更喜歡Either String ByteString來表示錯誤或解壓縮結果。

注意:此問題故意不顯示研究工作,因爲它立即以A風格的方式回答。

回答

1

您需要在這裏使用的功能從zlib被稱爲decompressWithErrors。它的值是遞歸DecompressStream數據結構,可以摺疊成ByteString使用v:fromDecompressStream

這裏有一個如何寫你要的功能,一個完整的例子:

import Data.Either 
import Codec.Compression.Zlib.Internal 
import qualified Data.ByteString.Lazy.Char8 as LB 

-- | Convert & unfold the custom DecompressStream 
-- error format from zlib to a Either 
decompressStreamToEither :: DecompressStream -> Either String LB.ByteString 
decompressStreamToEither (StreamError _ errmsg) = Left errmsg 
decompressStreamToEither [email protected](StreamChunk _ _) = Right $ fromDecompressStream stream 
decompressStreamToEither StreamEnd = Right $ "" 

-- | Decompress with explicit error handling 
safeDecompress :: LB.ByteString -> Either String LB.ByteString 
safeDecompress bstr = decompressStreamToEither $ decompressWithErrors gzipOrZlibFormat defaultDecompressParams bstr 

-- | Decompress gzip, if it fails, return uncompressed String 
decompressIfPossible :: LB.ByteString -> LB.ByteString 
decompressIfPossible bstr = 
    let conv (Left a) = bstr 
     conv (Right a) = a 
    in (conv . safeDecompress) bstr 

注意,這個例子gzipOrZlibFormat它會自動使用檢測頭是zlib還是gzip頭。