【问题标题】:Split lazy bytestring with another bytestring用另一个字节串拆分惰性字节串
【发布时间】:2017-12-02 09:34:46
【问题描述】:

如何将 lazy 字节串与另一个字节串(例如 "\r\n")分开?我正在寻找类似以下的功能:

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

我知道breakSubstring,但该函数仅适用于严格的字节串。我也看到了这个question,但解决方案是使用严格的字节串。

【问题讨论】:

  • 是在严格字节串之间进行转换,还是复制breakSubstring 的定义(它使用takeisPrefixOf 可用于惰性字节串)是一个合适的解决方案?
  • @user2407038 与 strict 相互转换不是一种选择。由于内存使用,我目前正在使用严格的字节串并尝试切换到惰性字节串。 breakSubString 函数使用了许多不适用于惰性字节串的 unsafeX 函数。也许我可以使用正常的功能。

标签: haskell lazy-evaluation bytestring


【解决方案1】:

回答我自己的问题:我创建了一个pull request,将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
            u@(_, 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 #-}

【讨论】:

    猜你喜欢
    • 2012-04-26
    • 2011-12-10
    • 2018-08-07
    • 2013-06-21
    • 1970-01-01
    • 1970-01-01
    • 2020-12-01
    • 1970-01-01
    • 2021-10-08
    相关资源
    最近更新 更多