haskell - 使用 Conduit 从 ByteString 过滤 ANSI 转义序列

标签 haskell conduit

我正在尝试制作一个从 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 的过滤内容。 ,但没有任何回应。

但是,如果我注释掉 ansiFilterdoConversionAndPrint ,回声确实有效,这让我喜欢 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/

相关文章:

haskell - 字符的重载字符串

haskell - Typo(?) ("composition") 七周内七种语言 - Haskell 部分

parsing - 从 Monad 状态上下文中解开值并连接两个状态上下文

list - Haskell 检查 Int 列表是否完整

haskell - Yesod respondSource 来自具有 PrimMonad 约束的源

haskell - 管道广播

list - 在haskell中创建循环列表的三种方法

multithreading - 有没有办法让管道从多个来源获取数据而不阻塞其中任何一个?

haskell - 使用 Conduits 从 rawQuery 中获取数据

haskell - 管道流中的并行处理