on master help sign in
Implement and test lazy split and splitWith
d5b4606Bryan O'Sullivan
Data/Text/Lazy.hs+36−2
@@ -107,8 +107,8 @@ module Data.Text.Lazy
107 , tails
107 , tails
108
108
109 -- ** Breaking into many substrings
109 -- ** Breaking into many substrings
110− -- , split
110+ , split
111− -- , splitWith
111+ , splitWith
112 -- , breakSubstring
112 -- , breakSubstring
113
113
114 -- ** Breaking into lines and words
114 -- ** Breaking into lines and words
@@ -646,6 +646,40 @@ tails ts@(Chunk t ts')
646 | T.length t == 1 = ts : tails ts'
646 | T.length t == 1 = ts : tails ts'
647 | otherwise = ts : tails (Chunk (T.unsafeTail t) ts')
647 | otherwise = ts : tails (Chunk (T.unsafeTail t) ts')
648
648
649+-- | /O(n)/ Break a 'Text' into pieces separated by the byte
650+-- argument, consuming the delimiter. I.e.
651+--
652+-- > split '\n' "a\nb\nd\ne" == ["a","b","d","e"]
653+-- > split 'a' "aXaXaXa" == ["","X","X","X",""]
654+-- > split 'x' "x" == ["",""]
655+--
656+-- and
657+--
658+-- > intercalate [c] . split c == id
659+-- > split == splitWith . (==)
660+--
661+-- As for all splitting functions in this library, this function does
662+-- not copy the substrings, it just constructs new 'Text's that are
663+-- slices of the original.
664+split :: Char -> Text -> [Text]
665+split c = splitWith (==c)
666+{-# INLINE split #-}
667+
668+-- | /O(n)/ Splits a 'Text' into components delimited by separators,
669+-- where the predicate returns True for a separator element. The
670+-- resulting components do not contain the separators. Two adjacent
671+-- separators result in an empty component in the output. eg.
672+--
673+-- > splitWith (=='a') "aabbaca" == ["","","bb","c",""]
674+-- > splitWith (=='a') [] == []
675+splitWith :: (Char -> Bool) -> Text -> [Text]
676+splitWith _ Empty = []
677+splitWith p (Chunk t0 ts0) = comb [] (T.splitWith p t0) ts0
678+ where comb acc (s:[]) Empty = revChunks (s:acc) : []
679+ comb acc (s:[]) (Chunk t ts) = comb (s:acc) (T.splitWith p t) ts
680+ comb acc (s:ss) ts = revChunks (s:acc) : comb [] ss ts
681+{-# INLINE splitWith #-}
682+
649revChunks :: [T.Text] -> Text
683revChunks :: [T.Text] -> Text
650revChunks = L.foldl' (flip chunk) Empty
684revChunks = L.foldl' (flip chunk) Empty
651
685
tests/Properties.hs+4
@@ -243,8 +243,10 @@ prop_T_tails = L.tails `eqP` (map unpackT . T.tails)
243prop_TL_tails = L.tails `eqP` (map unpackT . TL.tails)
243prop_TL_tails = L.tails `eqP` (map unpackT . TL.tails)
244
244
245prop_T_split_i c = id `eq` (T.intercalate (T.singleton c) . T.split c)
245prop_T_split_i c = id `eq` (T.intercalate (T.singleton c) . T.split c)
246+prop_TL_split_i c = id `eq` (TL.intercalate (TL.singleton c) . TL.split c)
246
247
247prop_T_splitWith p = splitWith p `eqP` (map unpackT . T.splitWith p)
248prop_T_splitWith p = splitWith p `eqP` (map unpackT . T.splitWith p)
249+prop_TL_splitWith p = splitWith p `eqP` (map unpackT . TL.splitWith p)
248
250
249splitWith _ "" = []
251splitWith _ "" = []
250splitWith p s = if null s'
252splitWith p s = if null s'
@@ -447,7 +449,9 @@ tests = [
447 ("prop_TL_tails", mytest prop_TL_tails),
449 ("prop_TL_tails", mytest prop_TL_tails),
448
450
449 ("prop_T_split_i", mytest prop_T_split_i),
451 ("prop_T_split_i", mytest prop_T_split_i),
452+ ("prop_TL_split_i", mytest prop_TL_split_i),
450 ("prop_T_splitWith", mytest prop_T_splitWith),
453 ("prop_T_splitWith", mytest prop_T_splitWith),
454+ ("prop_TL_splitWith", mytest prop_TL_splitWith),
451 ("prop_T_breakSubstringC", mytest prop_T_breakSubstringC),
455 ("prop_T_breakSubstringC", mytest prop_T_breakSubstringC),
452 ("prop_T_breakSubstring_isInfixOf", mytest prop_T_breakSubstring_isInfixOf),
456 ("prop_T_breakSubstring_isInfixOf", mytest prop_T_breakSubstring_isInfixOf),
453
457