2017-06-28 16 views
2

レイジーバイトコードを別のバイトコード(例えば"\r\n")に分割するにはどうすればよいですか?私は、次のような機能を探しています:別のバイトコードでレイジーのバイトコードを分割

BSL.ByteString -> BSL.ByteString -> [BSL.ByteString] 

は、私は約breakSubstringを知っているが、その機能は、厳密なバイト文字列でのみ使用可能です。私もこのquestionを見ましたが、解決策は厳密なバイトテストを使用しています。

+1

は厳密バイト文字列へ及びからの変換、または 'breakSubstring'(それが使用する' take'と 'isPrefixOfの定義をコピーしています'' Lazy bytestringsのために利用可能です)適切な解決策はありますか? – user2407038

+0

@ user2407038 strictからtoへの変換はオプションではありません。私は現在、厳密なバイトストリングを使用しており、メモリ使用量のために怠惰なバイトストリングに切り替えることを試みています。 [breakSubString](https://github.com/haskell/bytestring/blob/master/Data/ByteString.hs#L1350)関数は、レイジー・バイトストリングでは使用できないいくつかの 'unsafeX'関数を使用します。たぶん、私は通常の機能を使用することができます。 –

答えて

1

私自身の質問に答える:を作成しました。これはbreakSubstringからData.ByteString.Lazy(厳密なバージョンから適合)です。

プル要求がマージされるまで、次のコードを使用することができる。

{-# LANGUAGE BangPatterns #-} 

module Lib (breakSubstring) where 

import Data.Bits (finiteBitSize, shiftL, (.|.), (.&.)) 
import Data.Word (Word32) 
import Prelude 

import qualified Data.ByteString.Lazy as BSL 


breakSubstring 
    :: BSL.ByteString 
    -> BSL.ByteString 
    -> (BSL.ByteString, BSL.ByteString) 
breakSubstring pat = 
    case lp of 
    0 -> \src -> (BSL.empty, src) 
    1 -> BSL.break (== BSL.head pat) 
    _ -> if lp * 8 <= fromIntegral (finiteBitSize (0 :: Word)) 
      then shift 
      else karpRabin 
    where 
    lp = BSL.length pat 
    karpRabin :: BSL.ByteString -> (BSL.ByteString, BSL.ByteString) 
    karpRabin src 
     | BSL.length src < lp = (src, BSL.empty) 
     | otherwise = search (rollingHash $ BSL.take lp src) lp 
     where 
     k   = 2891336453 :: Word32 
     rollingHash = BSL.foldl' (\h b -> h * k + fromIntegral b) 0 
     hp   = rollingHash pat 
     m   = k^lp 
     get = fromIntegral . BSL.index src 
     search !hs !i 
      | hp == hs && pat == BSL.take lp b = u 
      | BSL.length src <= i    = (src, BSL.empty) 
      | otherwise      = search hs' (i + 1) 
      where 
      [email protected](_, b) = BSL.splitAt (i - lp) src 
      hs' = hs * k + 
        get i - 
        m * get (i - lp) 
    {-# INLINE karpRabin #-} 

    shift :: BSL.ByteString -> (BSL.ByteString, BSL.ByteString) 
    shift !src 
     | BSL.length src < lp = (src, BSL.empty) 
     | otherwise   = search (intoWord $ BSL.take lp src) lp 
     where 
     intoWord :: BSL.ByteString -> Word 
     intoWord = BSL.foldl' (\w b -> (w `shiftL` 8) .|. fromIntegral b) 0 
     wp = intoWord pat 
     mask = (1 `shiftL` fromIntegral (8 * lp)) - 1 
     search !w !i 
      | w == wp    = BSL.splitAt (i - lp) src 
      | BSL.length src <= i = (src, BSL.empty) 
      | otherwise   = search w' (i + 1) 
      where 
      b = fromIntegral (BSL.index src i) 
      w' = mask .&. ((w `shiftL` 8) .|. b) 
    {-# INLINE shift #-} 
関連する問題