gpt4 book ai didi

haskell - 在 Windows 上使用 Conduit 按行拆分

转载 作者:行者123 更新时间:2023-12-04 23:16:03 28 4
gpt4 key购买 nike

我在使用管道库逐行拆分文本时遇到了一些麻烦。

不幸的是,我正在使用的源数据与行尾极其不一致,其中包含 \r\n\n序列在同一个文件中。

我找到了 lines函数在 Data.Conduit.Binary ,但它按单个字节“拆分”( \n ,足够明智),这给我留下了尾随 \r在某些情况下。

我明白为什么当前的实现是这样工作的,我很有信心我可以一起破解某种解决方案,但我能想到的唯一方法是:

lines' = do
loop $ T.pack ""
where loop acc = do
char <- await
case char of
Nothing -> return ()
Just x -> do
case (isOver $ acc `T.append` x) of
(True,y) -> yield y
(False,y) -> loop y
where isOver n
| (T.takeEnd 2 n == _rLn) = (True, T.dropEnd 2 n)
| (T.takeEnd 1 n == _Ln) = (True, T.dropEnd 1 n)
| otherwise = (False,n)
where _rLn = T.pack $! "\r\n"
_Ln = T.pack $! "\n"

......这看起来不雅,笨拙,而且非常慢。

在每次迭代时检查最后两个字符感觉是错误的,因为我真正需要做的就是“记住”我读到的最后一个字符是否是 \r ,但我想不出一个明智的方法来做到这一点。

有没有人知道这个问题的更好解决方案?

最佳答案

不要试图重新发明轮子!我们仍然可以使用 conduit-combinators 制作更漂亮的东西.作为前言,如果您的 \r值永远不会出现,除非有时在换行符之前,您可以直接将它们过滤掉。也就是说,我将假设您的情况更普遍 - 您只想摆脱 \r后跟 \n 的值.

这个想法是使用 slidingWindowC 获得两个字符块,然后将这些块映射到它们的第一个字符 - 除非字符是 "\r\n" ,在这种情况下,我们将两者都丢弃。然后,删除了所有 \r后跟换行符,我们可以使用管道 linesUnboundedC .

{-# LANGUAGE TypeFamilies, FlexibleContexts #-}

import Data.Text (Text, singleton, empty)
import Data.MonoTraversable (Element, MonoFoldable)
import Conduit

main = runConduitRes $ (sourceFile "file.txt" :: Producer (ResourceT IO) Text)
.| linesUnboundedC'
.| printC

-- | Converted a chunked input of characters into lines delimited by \n or \r\n
linesUnboundedC'
:: (Element a ~ Char, MonoFoldable a, Monad m) => ConduitM a Text m ()
linesUnboundedC' = concatMapC id
.| slidingWindowC 2
.| mapC (\cs@[c,_] -> if cs == "\r\n" then empty else singleton c)
.| linesUnboundedC

关于haskell - 在 Windows 上使用 Conduit 按行拆分,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41702549/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com