-- | -- Module : Data.ByteString.Lazy.Char8 -- Copyright : (c) Don Stewart 2006-2008 -- (c) Duncan Coutts 2006-2011 -- License : BSD-style -- -- Maintainer : dons00@gmail.com, duncan@community.haskell.org -- Stability : stable -- Portability : portable -- -- Manipulate /lazy/ 'ByteString's using 'Char' operations. All Chars will -- be truncated to 8 bits. It can be expected that these functions will -- run at identical speeds to their 'Data.Word.Word8' equivalents in -- "Data.ByteString.Lazy". -- -- This module is intended to be imported @qualified@, to avoid name -- clashes with "Prelude" functions. eg. -- -- > import qualified Data.ByteString.Lazy.Char8 as C -- -- The Char8 interface to bytestrings provides an instance of IsString -- for the ByteString type, enabling you to use string literals, and -- have them implicitly packed to ByteStrings. -- Use @{-\# LANGUAGE OverloadedStrings \#-}@ to enable this. -- module Data.ByteString.Lazy.Char8 ( -- * The @ByteString@ type ByteString, -- * Introducing and eliminating 'ByteString's L.empty, singleton, pack, unpack, L.fromChunks, L.toChunks, L.fromStrict, L.toStrict, -- * Basic interface cons, --cons', snoc, L.append, head, uncons, last, L.tail, unsnoc, L.init, L.null, L.length, -- * Transforming ByteStrings map, L.reverse, intersperse, L.intercalate, L.transpose, -- * Reducing 'ByteString's (folds) foldl, foldl', foldl1, foldl1', foldr, foldr', foldr1, foldr1', -- ** Special folds L.concat, concatMap, any, all, maximum, minimum, L.compareLength, -- * Building ByteStrings -- ** Scans scanl, scanl1, scanr, scanr1, -- ** Accumulating maps mapAccumL, mapAccumR, -- ** Infinite ByteStrings repeat, replicate, L.cycle, iterate, -- ** Unfolding ByteStrings unfoldr, -- * Substrings -- ** Breaking strings L.take, L.takeEnd, L.drop, L.dropEnd, L.splitAt, takeWhile, takeWhileEnd, dropWhile, dropWhileEnd, span, spanEnd, break, breakEnd, L.group, groupBy, L.inits, L.tails, L.initsNE, L.tailsNE, L.stripPrefix, L.stripSuffix, -- ** Breaking into many substrings split, splitWith, -- ** Breaking into lines and words lines, words, unlines, unwords, -- * Predicates L.isPrefixOf, L.isSuffixOf, -- * Searching ByteStrings -- ** Searching by equality elem, notElem, -- ** Searching with a predicate find, filter, partition, -- * Indexing ByteStrings index, indexMaybe, (!?), elemIndex, elemIndexEnd, elemIndices, findIndex, findIndexEnd, findIndices, count, -- * Zipping and unzipping ByteStrings zip, zipWith, packZipWith, unzip, -- * Ordered ByteStrings -- sort, -- * Low level conversions -- ** Copying ByteStrings L.copy, -- * Reading from ByteStrings -- | Note that a lazy 'ByteString' may hold an unbounded stream of -- @\'0\'@ digits, in which case the functions below may never return. -- If that's a concern, you can use 'take' to first truncate the input -- to an acceptable length. Non-termination is also possible when -- reading arbitrary precision numbers via 'readInteger' or -- 'readNatural', if the input is an unbounded stream of arbitrary -- decimal digits. -- --readInt, --readInt64, --readInt32, --readInt16, --readInt8, --readWord, --readWord64, --readWord32, --readWord16, --readWord8, --readInteger, --readNatural, -- * I\/O with 'ByteString's -- | ByteString I/O uses binary mode, without any character decoding -- or newline conversion. The fact that it does not respect the Handle -- newline mode is considered a flaw and may be changed in a future version. -- ** Standard input and output L.getContents, L.putStr, putStrLn, L.interact, -- ** Files L.readFile, L.writeFile, L.appendFile, -- ** I\/O with Handles L.hGetContents, L.hGet, L.hGetNonBlocking, L.hPut, L.hPutNonBlocking, L.hPutStr, hPutStrLn, ) where import qualified Prelude () import MiniPrelude as P import Data.ByteString.Lazy (ByteString) import qualified Data.ByteString.Lazy as L import qualified Data.ByteString as S (ByteString) -- typename only import qualified Data.ByteString as B import qualified Data.ByteString.Unsafe as B import Data.List.NonEmpty (NonEmpty(..)) import Data.ByteString.Internal (c2w, w2c) import Data.Int (Int64) import qualified Data.List as List import System.IO.Base (Handle, stdout) ------------------------------------------------------------------------ singleton :: Char -> ByteString singleton = L.singleton . c2w pack :: [Char] -> ByteString pack = L.pack . P.map c2w unpack :: ByteString -> [Char] unpack = P.map w2c . L.unpack infixr 5 `cons`, `cons'` --same as list (:) infixl 5 `snoc` cons :: Char -> ByteString -> ByteString cons = L.cons . c2w --cons' :: Char -> ByteString -> ByteString --cons' = L.cons' . c2w snoc :: ByteString -> Char -> ByteString snoc p = L.snoc p . c2w head :: ByteString -> Char head = w2c . L.head uncons :: ByteString -> Maybe (Char, ByteString) uncons bs = case L.uncons bs of Nothing -> Nothing Just (w, bs') -> Just (w2c w, bs') unsnoc :: ByteString -> Maybe (ByteString, Char) unsnoc bs = case L.unsnoc bs of Nothing -> Nothing Just (bs', w) -> Just (bs', w2c w) last :: ByteString -> Char last = w2c . L.last map :: (Char -> Char) -> ByteString -> ByteString map f = L.map (c2w . f . w2c) intersperse :: Char -> ByteString -> ByteString intersperse = L.intersperse . c2w foldl :: (a -> Char -> a) -> a -> ByteString -> a foldl f = L.foldl (\a c -> f a (w2c c)) foldl' :: (a -> Char -> a) -> a -> ByteString -> a foldl' f = L.foldl' (\a c -> f a (w2c c)) foldr :: (Char -> a -> a) -> a -> ByteString -> a foldr f = L.foldr (f . w2c) foldr' :: (Char -> a -> a) -> a -> ByteString -> a foldr' f = L.foldr' (f . w2c) foldl1 :: (Char -> Char -> Char) -> ByteString -> Char foldl1 f ps = w2c (L.foldl1 (\x y -> c2w (f (w2c x) (w2c y))) ps) foldl1' :: (Char -> Char -> Char) -> ByteString -> Char foldl1' f ps = w2c (L.foldl1' (\x y -> c2w (f (w2c x) (w2c y))) ps) foldr1 :: (Char -> Char -> Char) -> ByteString -> Char foldr1 f ps = w2c (L.foldr1 (\x y -> c2w (f (w2c x) (w2c y))) ps) foldr1' :: (Char -> Char -> Char) -> ByteString -> Char foldr1' f ps = w2c (L.foldr1' (\x y -> c2w (f (w2c x) (w2c y))) ps) concatMap :: (Char -> ByteString) -> ByteString -> ByteString concatMap f = L.concatMap (f . w2c) any :: (Char -> Bool) -> ByteString -> Bool any f = L.any (f . w2c) all :: (Char -> Bool) -> ByteString -> Bool all f = L.all (f . w2c) maximum :: ByteString -> Char maximum = w2c . L.maximum minimum :: ByteString -> Char minimum = w2c . L.minimum scanl :: (Char -> Char -> Char) -> Char -> ByteString -> ByteString scanl f z = L.scanl (\a b -> c2w (f (w2c a) (w2c b))) (c2w z) scanl1 :: (Char -> Char -> Char) -> ByteString -> ByteString scanl1 f = L.scanl1 f' where f' accumulator value = c2w (f (w2c accumulator) (w2c value)) scanr :: (Char -> Char -> Char) -- ^ element -> accumulator -> new accumulator -> Char -- ^ starting value of accumulator -> ByteString -- ^ input of length n -> ByteString -- ^ output of length n+1 scanr f = L.scanr f' . c2w where f' accumulator value = c2w (f (w2c accumulator) (w2c value)) scanr1 :: (Char -> Char -> Char) -> ByteString -> ByteString scanr1 f = L.scanr1 f' where f' accumulator value = c2w (f (w2c accumulator) (w2c value)) mapAccumL :: (acc -> Char -> (acc, Char)) -> acc -> ByteString -> (acc, ByteString) mapAccumL f = L.mapAccumL (\a w -> case f a (w2c w) of (a',c) -> (a', c2w c)) mapAccumR :: (acc -> Char -> (acc, Char)) -> acc -> ByteString -> (acc, ByteString) mapAccumR f = L.mapAccumR (\acc w -> case f acc (w2c w) of (acc', c) -> (acc', c2w c)) iterate :: (Char -> Char) -> Char -> ByteString iterate f = L.iterate (c2w . f . w2c) . c2w repeat :: Char -> ByteString repeat = L.repeat . c2w replicate :: Int64 -> Char -> ByteString replicate w c = L.replicate w (c2w c) unfoldr :: (a -> Maybe (Char, a)) -> a -> ByteString unfoldr f = L.unfoldr $ \a -> case f a of Nothing -> Nothing Just (c, a') -> Just (c2w c, a') takeWhile :: (Char -> Bool) -> ByteString -> ByteString takeWhile f = L.takeWhile (f . w2c) takeWhileEnd :: (Char -> Bool) -> ByteString -> ByteString takeWhileEnd f = L.takeWhileEnd (f . w2c) dropWhile :: (Char -> Bool) -> ByteString -> ByteString dropWhile f = L.dropWhile (f . w2c) dropWhileEnd :: (Char -> Bool) -> ByteString -> ByteString dropWhileEnd f = L.dropWhileEnd (f . w2c) break :: (Char -> Bool) -> ByteString -> (ByteString, ByteString) break f = L.break (f . w2c) breakEnd :: (Char -> Bool) -> ByteString -> (ByteString, ByteString) breakEnd f = L.breakEnd (f . w2c) span :: (Char -> Bool) -> ByteString -> (ByteString, ByteString) span f = L.span (f . w2c) spanEnd :: (Char -> Bool) -> ByteString -> (ByteString, ByteString) spanEnd f = L.spanEnd (f . w2c) split :: Char -> ByteString -> [ByteString] split = L.split . c2w splitWith :: (Char -> Bool) -> ByteString -> [ByteString] splitWith f = L.splitWith (f . w2c) groupBy :: (Char -> Char -> Bool) -> ByteString -> [ByteString] groupBy k = L.groupBy (\a b -> k (w2c a) (w2c b)) index :: ByteString -> Int64 -> Char index = (w2c .) . L.index indexMaybe :: ByteString -> Int64 -> Maybe Char indexMaybe = (fmap w2c .) . L.indexMaybe (!?) :: ByteString -> Int64 -> Maybe Char (!?) = indexMaybe elemIndex :: Char -> ByteString -> Maybe Int64 elemIndex = L.elemIndex . c2w elemIndexEnd :: Char -> ByteString -> Maybe Int64 elemIndexEnd = L.elemIndexEnd . c2w elemIndices :: Char -> ByteString -> [Int64] elemIndices = L.elemIndices . c2w findIndex :: (Char -> Bool) -> ByteString -> Maybe Int64 findIndex f = L.findIndex (f . w2c) findIndexEnd :: (Char -> Bool) -> ByteString -> Maybe Int64 findIndexEnd f = L.findIndexEnd (f . w2c) findIndices :: (Char -> Bool) -> ByteString -> [Int64] findIndices f = L.findIndices (f . w2c) count :: Char -> ByteString -> Int64 count c = L.count (c2w c) elem :: Char -> ByteString -> Bool elem c = L.elem (c2w c) notElem :: Char -> ByteString -> Bool notElem c = L.notElem (c2w c) filter :: (Char -> Bool) -> ByteString -> ByteString filter f = L.filter (f . w2c) partition :: (Char -> Bool) -> ByteString -> (ByteString, ByteString) partition f = L.partition (f . w2c) find :: (Char -> Bool) -> ByteString -> Maybe Char find f ps = w2c `fmap` L.find (f . w2c) ps zip :: ByteString -> ByteString -> [(Char,Char)] zip ps qs | L.null ps || L.null qs = [] | otherwise = (head ps, head qs) : zip (L.tail ps) (L.tail qs) zipWith :: (Char -> Char -> a) -> ByteString -> ByteString -> [a] zipWith f = L.zipWith ((. w2c) . f . w2c) packZipWith :: (Char -> Char -> Char) -> ByteString -> ByteString -> ByteString packZipWith f = L.packZipWith f' where f' c1 c2 = c2w $ f (w2c c1) (w2c c2) unzip :: [(Char, Char)] -> (ByteString, ByteString) unzip ls = (pack (fmap fst ls), pack (fmap snd ls)) lines :: ByteString -> [ByteString] lines bs | L.null bs = [] | otherwise = case elemIndex '\n' bs of Nothing -> [bs] Just n -> L.take n bs : lines (L.drop (n + 1) bs) unlines :: [ByteString] -> ByteString unlines = List.foldr (\x t -> x `L.append` cons '\n' t) L.empty words :: ByteString -> [ByteString] words = List.filter (not . L.null) . splitWith isSpace unwords :: [ByteString] -> ByteString unwords = L.intercalate (singleton ' ') hPutStrLn :: Handle -> ByteString -> IO () hPutStrLn h ps = L.hPut h ps >> L.hPut h (L.singleton 0x0a) putStrLn :: ByteString -> IO () putStrLn = hPutStrLn stdout