替换字节字符串中的换行符



我想要一个函数,它接受一个字节字符串并将换行符nnr替换为逗号,但想不出一个好方法。

import qualified Data.ByteString as BS
import Data.Char (ord) 
import Data.Word (Word8)
endlWord8 = fromIntegral $ ord 'n' :: Word8
replace :: BS.ByteString -> BS.ByteString

我想使用BS.map但看不出如何,因为我无法在Word8上进行模式匹配。另一种选择是BS.split,然后加入 Word8 逗号,但这听起来缓慢且不优雅。有什么想法吗?

使用Data.ByteString.Char8来摆脱讨厌的Word8Char你必须做的转换。根据Data.ByteString.Char8,第一句话的性能不应该被改变。

此外,使用B.span而不是B.split,因为您要替换nr组合,而不仅仅是n

我自己(可能是笨拙的(尝试这样做:

module Test where
import Data.Monoid ((<>))
import Data.ByteString.Char8 (ByteString)
import qualified Data.ByteString.Char8 as B
import qualified Data.ByteString.Builder as Build
import qualified Data.ByteString.Lazy as LB
eatNewline :: ByteString -> (Maybe Char, ByteString)
eatNewline string
  | B.null string = (Nothing, string)
  | B.head string == 'n' && B.null (B.tail string) = (Just ',', B.empty)
  | B.head string == 'n' && B.head (B.tail string) /= 'r' = (Just ',', B.drop 1 string)
  | B.head string == 'n' && B.head (B.tail string) == 'r' = (Just ',', B.drop 2 string)
  | otherwise = (Nothing, string)
replaceNewlines :: ByteString -> ByteString
replaceNewlines = LB.toStrict . Build.toLazyByteString . go mempty
  where
    go :: Build.Builder -> ByteString -> Build.Builder
    go builder string = let (chunk, rest) = B.span (/= 'n') string
                            (c, rest1)    = eatNewline rest
                            maybeComma    = maybe mempty Build.char8 c
                        in if B.null rest1 then
                             builder <> Build.byteString chunk <> maybeComma
                           else
                             go (builder <> Build.byteString chunk <> maybeComma) rest1

希望 Data.ByteString.Buildermappend在已经用于其操作数之一的次数上不是线性的mappend否则,这里将有一个二次算法。

最新更新