我正在尝试制作一个从 ByteStrings 过滤 ANSI 转义码的导管。我想出了一个函数,它将 ByteString 转换为 Word8 的流,进行过滤,最后转换回 ByteStream 流。
当我在 GHCi 中使用它时,它似乎工作正常:
> runConduit $ yield "hello\27[23;1m world" .| ansiFilter .| printC
"hello world"
当我在我的应用程序中使用它时,包含
ansiFilter
的管道似乎没有通过任何东西。这是完整的来源:{-# LANGUAGE OverloadedStrings #-}
module Main where
import Conduit
import Control.Concurrent.Async
import Control.Concurrent.STM
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import Data.Conduit.TQueue
import Data.Word8 (Word8)
import qualified Data.Word8 as Word8
main :: IO ()
main = do
queue <- atomically $ newTBQueue 25
let qSource = sourceTBQueue queue
atomically $ writeTBQueue queue ("hello" :: ByteString)
race_
(putInputIntoQueue queue)
(doConversionAndPrint qSource)
putInputIntoQueue q =
runConduit
$ stdinC
.| iterMC (atomically . writeTBQueue q)
.| sinkNull
doConversionAndPrint src =
runConduit
$ src
.| ansiFilter
.| stdoutC
ansiFilter :: MonadIO m => ConduitM ByteString ByteString m ()
ansiFilter = toWord8 .| ansiFilter' .| toByteString
where
ansiFilter' = awaitForever $ \first -> do
msecond <- peekC
case (first, msecond) of
(0x1b, Just 0x5b) -> do
dropWhileC (not . Word8.isLetter)
dropC 1
_ -> yield first
toWord8 = concatC
toByteString :: Monad m => ConduitM Word8 ByteString m ()
toByteString =
(mapC BS.singleton .| foldC) >>= yield
这个程序应该回显
stdin
的过滤内容。 ,但没有任何回应。但是,如果我注释掉
ansiFilter
在 doConversionAndPrint
,回声确实有效,这让我喜欢 ansiFilter
功能错误。任何帮助将不胜感激!
最佳答案
我重新实现了 ansiFilter
就管道组合器中更高级别的分 block 数据功能而言,如 takeWhileCE
.这似乎可行,并且应该通过让更多数据保留在有效的内存表示中来提高效率:
ansiFilter :: MonadIO m => ConduitM ByteString ByteString m ()
ansiFilter = loop
where
loop = do
takeWhileCE (/= 0x1b)
mfirst <- headCE
case mfirst of
Nothing -> return ()
Just first -> assert (first == 0x1b) $ do
msecond <- peekCE
case msecond of
Just 0x5b -> do
dropWhileCE (not . Word8.isLetter)
dropCE 1
_ -> yield $ BS.singleton first
loop
关于haskell - 使用 Conduit 从 ByteString 过滤 ANSI 转义序列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41030290/