@@ -1,4 +1,5 @@
1{-# OPTIONS_GHC -fno-warn-orphans #-}
1{-# OPTIONS_GHC -fno-warn-orphans #-}
2+{-# LANGUAGE BangPatterns #-}
3-- Module : Data.Text.Lazy
4-- Module : Data.Text.Lazy
4-- Copyright : (c) Bryan O'Sullivan 2009
5-- Copyright : (c) Bryan O'Sullivan 2009
@@ -57,6 +58,7 @@ module Data.Text.Lazy
57 , intersperse
58 , intersperse
58 , transpose
59 , transpose
61 -- ** Case conversion
63 -- ** Case conversion
@@ -109,6 +111,11 @@ module Data.Text.Lazy
110 , takeWhile
112 , takeWhile
111 , dropWhile
113 , dropWhile
112 , splitAt
119 , splitAt
@@ -118,7 +125,10 @@ module Data.Text.Lazy
120 -- ** Breaking into many substrings
127 -- ** Breaking into many substrings
122 , splitWith
132 , splitWith
123 , chunksOf
133 , chunksOf
124 -- , breakSubstring
134 -- , breakSubstring
@@ -160,7 +170,7 @@ module Data.Text.Lazy
161import Prelude (Char, Bool(..), Int, Maybe(..), String,
171import Prelude (Char, Bool(..), Int, Maybe(..), String,
162 Eq(..), Ord(..), Read(..), Show(..),
172 Eq(..), Ord(..), Read(..), Show(..),
163− (&&), (+), (-), (.), ($), (++),
173+ (&&), (||), (+), (-), (.), ($), (++),
164 div, flip, fromIntegral, not, otherwise)
174 div, flip, fromIntegral, not, otherwise)
165import qualified Prelude as P
175import qualified Prelude as P
166import Data.Int (Int64)
176import Data.Int (Int64)
@@ -430,6 +440,14 @@ reverse = rev Empty
430 where rev a Empty = a
440 where rev a Empty = a
431 rev a (Chunk t ts) = rev (Chunk (T.reverse t) a) ts
441 rev a (Chunk t ts) = rev (Chunk (T.reverse t) a) ts
443+-- | /O(m)*O(n)/ Replace every occurrence of one substring with another.
444+replace :: Text -- ^ Text to search for
445+ -> Text -- ^ Replacement text
446+ -> Text -- ^ Input text
448+replace s d = intercalate d . split s
449+{-# INLINE replace #-}
433-- ----------------------------------------------------------------------------
451-- ----------------------------------------------------------------------------
434-- ** Case conversions (folds)
452-- ** Case conversions (folds)
@@ -662,7 +680,7 @@ take i t0 = take' i t0
662-- | /O(n)/ 'drop' @n@, applied to a 'Text', returns the suffix of the
680-- | /O(n)/ 'drop' @n@, applied to a 'Text', returns the suffix of the
663-- 'Text' of length @n@, or the empty 'Text' if @n@ is greater than the
681-- 'Text' of length @n@, or the empty 'Text' if @n@ is greater than the
664-- length of the 'Text'. Subject to fusion.
682-- length of the 'Text'. Subject to fusion.
665−drop :: Int -> Text -> Text
683+drop :: Int64 -> Text -> Text
667 | i <= 0 = t0
685 | i <= 0 = t0
668 | otherwise = drop' i t0
686 | otherwise = drop' i t0
@@ -718,6 +736,52 @@ dropWhile p t0 = dropWhile' t0
718"LAZY TEXT dropWhile -> unfused" [1] forall p t.
736"LAZY TEXT dropWhile -> unfused" [1] forall p t.
719 unstream (S.dropWhile p (stream t)) = dropWhile p t
737 unstream (S.dropWhile p (stream t)) = dropWhile p t
739+-- | /O(n)/ 'dropWhileEnd' @p@ @t@ returns the prefix remaining after
740+-- dropping characters that fail the predicate @p@ from the end of
744+-- > dropWhileEnd (=='.') "foo..." == "foo"
745+dropWhileEnd :: (Char -> Bool) -> Text -> Text
747+ where go Empty = Empty
748+ go (Chunk t Empty) = if T.null t'
751+ where t' = T.dropWhileEnd p t
752+ go (Chunk t ts) = case go ts of
753+ Empty -> go (Chunk t Empty)
755+{-# INLINE dropWhileEnd #-}
757+-- | /O(n)/ 'dropAround' @p@ @t@ returns the substring remaining after
758+-- dropping characters that fail the predicate @p@ from both the
759+-- beginning and end of @t@. Subject to fusion.
760+dropAround :: (Char -> Bool) -> Text -> Text
761+dropAround p = dropWhile p . dropWhileEnd p
762+{-# INLINE [1] dropAround #-}
764+-- | /O(n)/ Remove leading white space from a string. Equivalent to:
766+-- > dropWhile isSpace
767+stripStart :: Text -> Text
768+stripStart = dropWhile isSpace
769+{-# INLINE [1] stripStart #-}
771+-- | /O(n)/ Remove trailing white space from a string. Equivalent to:
773+-- > dropWhileEnd isSpace
774+stripEnd :: Text -> Text
775+stripEnd = dropWhileEnd isSpace
776+{-# INLINE [1] stripEnd #-}
778+-- | /O(n)/ Remove leading and trailing white space from a string.
781+-- > dropAround isSpace
782+strip :: Text -> Text
783+strip = dropAround isSpace
784+{-# INLINE [1] strip #-}
722-- | /O(n)/ 'splitAt' @n t@ returns a pair whose first element is a
786-- | /O(n)/ 'splitAt' @n t@ returns a pair whose first element is a
723-- prefix of @t@ of length @n@, and whose second is the remainder of
787-- prefix of @t@ of length @n@, and whose second is the remainder of
@@ -791,24 +855,93 @@ tails ts@(Chunk t ts')
791 | T.length t == 1 = ts : tails ts'
855 | T.length t == 1 = ts : tails ts'
792 | otherwise = ts : tails (Chunk (T.unsafeTail t) ts')
856 | otherwise = ts : tails (Chunk (T.unsafeTail t) ts')
860+-- Splitting functions in this library do not perform character-wise
861+-- copies to create substrings; they just construct new 'Text's that
862+-- are slices of the original.
794−-- | /O(n)/ Break a 'Text' into pieces separated by the byte
864+-- | /O(m)*O(n)/ Break a 'Text' into pieces separated by the first
795−-- argument, consuming the delimiter. I.e.
865+-- 'Text' argument, consuming the delimiter. Examples:
797−-- > split '\n' "a\nb\nd\ne" == ["a","b","d","e"]
867+-- > split "\r\n" "a\r\nb\r\nd\r\ne" == ["a","b","d","e"]
798−-- > split 'a' "aXaXaXa" == ["","X","X","X",""]
868+-- > split "aaa" "aaaXaaaXaaaXaaa" == ["","X","X","X",""]
799−-- > split 'x' "x" == ["",""]
869+-- > split "x" "x" == ["",""]
803−-- > intercalate [c] . split c == id
873+-- > intercalate s . split s == id
874+-- > split (singleton c) == splitWith (==c)
875+split :: Text -- ^ Text to split on
876+ -> Text -- ^ Input text
804−-- > split == splitWith . (==)
880+ | l == 1 = splitWith (== (head pat)) src0
805−--
881+ | otherwise = go src0
806−-- As for all splitting functions in this library, this function does
882+ where
807−-- not copy the substrings, it just constructs new 'Text's that are
883+ l = length pat
808−-- slices of the original.
884+ go src = search 0 src
809−split :: Char -> Text -> [Text]
885+ where
810−split c = splitWith (==c)
886+ search !n !s
887+ | null s = [src] -- not found
888+ | pat `isPrefixOf` s = take n src : go (drop l s)
889+ | otherwise = search (n+1) (tail s)
890+{-# INLINE [1] split #-}
893+"LAZY TEXT split/singleton -> splitWith/==" [~1] forall c t.
894+ split (singleton c) t = splitWith (==c) t
897+-- | /O(m)*O(n)/ Break a 'Text' into pieces at most @k@ times,
898+-- treating the first 'Text' argument as the delimiter to break on,
899+-- and consuming the delimiter. The last element of the list contains
900+-- the remaining text after the number of times to split has been
901+-- reached. A value of zero or less for @k@ causes no splitting to
906+-- > splitTimes 0 "//" "a//b//c" == ["a//b//c"]
907+-- > splitTimes 2 ":" "a:b:c:d:e" == ["a","b","c:d:e"]
908+-- > splitTimes 100 "???" "a????b" == ["a","?b"]
912+-- > intercalate s . splitTimes k s == id
913+splitTimes :: Int64 -- ^ Maximum number of times to split
914+ -> Text -- ^ Text to split on
915+ -> Text -- ^ Input text
917+splitTimes k pat src0
918+ | k <= 0 || l == 0 = [src0]
919+ | otherwise = go k src0
922+ go !i src = search 0 src
925+ | i == 0 || null s = [src] -- not found or limit reached
926+ | pat `isPrefixOf` s = take n src : go (i-1) (drop l s)
927+ | otherwise = search (n+1) (tail s)
928+{-# INLINE splitTimes #-}
930+-- | /O(m)*O(n)/ Break a 'Text' into pieces at most @k@ times, like
931+-- 'splitTimes', but start from the end of the input and work towards
936+-- > splitTimes 2 "::" "a::b::c::d::e" == ["a","b","c::d::e"]
937+-- > splitTimesEnd 2 "::" "a::b::c::d::e" == ["a::b::c","d","e"]
938+splitTimesEnd :: Int64 -- ^ Maximum number of times to split
939+ -> Text -- ^ Text to split on
940+ -> Text -- ^ Input text
942+splitTimesEnd k pat src =
943+ L.reverse . L.map reverse $ splitTimes k (reverse pat) (reverse src)
811−{-# INLINE split #-}
944+{-# INLINE splitTimesEnd #-}
813-- | /O(n)/ Splits a 'Text' into components delimited by separators,
946-- | /O(n)/ Splits a 'Text' into components delimited by separators,
814-- where the predicate returns True for a separator element. The
947-- where the predicate returns True for a separator element. The