44 lines
1.6 KiB
Plaintext
44 lines
1.6 KiB
Plaintext
module Pipes.String where
|
|
|
|
import Prelude
|
|
|
|
import Control.Monad.Maybe.Trans (MaybeT(..), runMaybeT)
|
|
import Control.Monad.Rec.Class (whileJust)
|
|
import Control.Monad.ST.Class (liftST)
|
|
import Control.Monad.Trans.Class (lift)
|
|
import Data.Array.ST as Array.ST
|
|
import Data.Foldable (fold, traverse_)
|
|
import Data.Maybe (Maybe(..))
|
|
import Data.String (Pattern)
|
|
import Data.String as String
|
|
import Effect.Class (class MonadEffect, liftEffect)
|
|
import Pipes (await, yield)
|
|
import Pipes.Core (Pipe)
|
|
|
|
-- | Accumulate string chunks until `pat` is seen, then `yield` the buffered
|
|
-- | string up to (and not including) the pattern.
|
|
-- |
|
|
-- | When end-of-stream is reached, yields the remaining buffered string then `Nothing`.
|
|
-- |
|
|
-- | ```
|
|
-- | toList $ yield "foo,bar,baz" >-> split ","
|
|
-- | -- "foo" : "bar" : "baz" : Nil
|
|
-- | ```
|
|
split :: forall m. MonadEffect m => Pattern -> Pipe (Maybe String) (Maybe String) m Unit
|
|
split pat = do
|
|
buf <- liftEffect $ liftST $ Array.ST.new
|
|
whileJust $ runMaybeT do
|
|
chunk <- MaybeT await
|
|
case String.indexOf pat chunk of
|
|
Nothing -> void $ liftEffect $ liftST $ Array.ST.push chunk buf
|
|
Just ix -> do
|
|
let
|
|
{ before, after } = String.splitAt ix chunk
|
|
len <- liftEffect $ liftST $ Array.ST.length buf
|
|
buf' <- liftEffect $ liftST $ Array.ST.splice 0 len [] buf
|
|
lift $ yield $ Just $ (fold buf') <> before
|
|
void $ liftEffect $ liftST $ Array.ST.push (String.drop 1 after) buf
|
|
buf' <- liftEffect $ liftST $ Array.ST.unsafeFreeze buf
|
|
traverse_ yield (Just <$> String.split pat (fold buf'))
|
|
yield Nothing
|