on master help sign in
Fix up the type of find, and add a break function.

--HG-- extra : convert_revision : 459f8e547bc07522e8ad50c2f546904e12594602

commit0e92d3f7f098180a365cd3b0d265a87146c1886c authorBryan O'Sullivan <bos@serpentine.com> dateTue 6 Oct 2009, 21:42 (17 years ago) parent40ac812
2 files changed+45−35
Data/Text.hs+44−18 tests/Properties.hs+1−17
Data/Text.hs+44−18
@@ -115,6 +115,7 @@ module Data.Text
115115 , stripEnd
116116 , splitAt
117117 , spanBy
118+ , break
118119 , breakBy
119120 , group
120121 , groupBy
@@ -124,7 +125,6 @@ module Data.Text
124125 -- ** Breaking into many substrings
125126 -- $split
126127 , split
127− , splitTimes
128128 , splitTimesEnd
129129 , splitBy
130130 , chunksOf
@@ -1051,35 +1051,62 @@ filter :: (Char -> Bool) -> Text -> Text
10511051filter p t = unstream (S.filter p (stream t))
10521052{-# INLINE filter #-}
10531053
1054−-- /O(n+m)/ Find all non-overlapping instances of @needle@ in
1055−-- @haystack@. The first element of the returned tuple is the prefix
1056−-- of @haystack@ before any matches of @needle@. The second element
1057−-- of the tuple is a list of non-overlapping substrings from
1058−-- @haystack@. Each begins with @needle@ and ends just before the
1059−-- following match. If @needle@ is not present in @haystack@, the
1060−-- list will be empty and the prefix will contain @haystack@.
1054+-- | /O(n+m)/ Find the first instance of @needle@ in @haystack@. The
1055+-- first element of the returned tuple is the prefix of @haystack@
1056+-- before @needle@ is matched. The second is the remainder of
1057+-- @haystack@, starting with the match.
10611058--
10621059-- Examples:
10631060--
1064−-- > find "::" "a::b::c" ==> ("a", ["::b", "::c"])
1065−-- > find "/" "foobar" ==> ("foobar", [])
1061+-- > break "::" "a::b::c" ==> ("a", "::b::c")
1062+-- > break "/" "foobar" ==> ("foobar", "")
10661063--
10671064-- Laws:
10681065--
1069−-- > concat (prefix : matches) == haystack
1070−-- > where (prefix, matches) = find needle haystack
1066+-- > append prefix match == haystack
1067+-- > where (prefix, match) = break needle haystack
1068+--
1069+-- If you need to break a string by a substring repeatedly (e.g. you
1070+-- want to break on every instance of a substring), use 'find'
1071+-- instead, as it has lower startup overhead.
10711072--
10721073-- In (unlikely) bad cases, this function's time complexity
10731074-- degenerates towards /O(n*m)/.
1074−find :: Text -> Text -> (Text, [Text])
1075+break :: Text -> Text -> (Text, Text)
1076+break pat src@(Text arr off len)
1077+ | null pat = emptyError "break"
1078+ | otherwise = case indices pat src of
1079+ [] -> (src, empty)
1080+ (x:_) -> (textP arr off x, textP arr (off+x) (len-x))
1081+{-# INLINE break #-}
1082+
1083+-- | /O(n+m)/ Find all non-overlapping instances of @needle@ in
1084+-- @haystack@. The first element of the returned pair is the prefix
1085+-- of @haystack@ prior to any matches of @needle@. The second is a
1086+-- list of pairs.
1087+--
1088+-- The first element of each pair in the list is a span from the
1089+-- beginning of a match to the beginning of the next match, while the
1090+-- second is a span from the beginning of the match to the end of the
1091+-- input.
1092+--
1093+-- Examples:
1094+--
1095+-- > find "::" ""
1096+-- > ==> ("", [])
1097+-- > find "/" "a/b/c/d"
1098+-- > ==> ("a", [("/b","/b/c/d"), ("/c","/c/d"), ("/d","/d")])
1099+find :: Text -> Text -> (Text, [(Text, Text)])
10751100find pat src@(Text arr off len)
10761101 | null pat = emptyError "find"
10771102 | otherwise = case indices pat src of
10781103 [] -> (src, [])
1079− (x:xs) -> (textP arr off x, go x xs)
1104+ (x:xs) -> (chunk 0 x, go x xs)
10801105 where
1081− go !s (x:xs) = textP arr (s+off) (x-s) : go x xs
1082− go s _ = [textP arr (s+off) (len-s)]
1106+ go !s (x:xs) = (chunk s (x-s), chunk s (len-s)) : go x xs
1107+ go s _ = let c = chunk s (len-s)
1108+ in [(c,c)]
1109+ chunk !n !l = textP arr (n+off) l
10831110{-# INLINE find #-}
10841111
10851112-------------------------------------------------------------------------------
@@ -1099,8 +1126,7 @@ find pat src@(Text arr off len)
10991126-- For example, suppose you have a string that you want to split on
11001127-- the substring @\"::\"@, such as @\"foo::bar::quux\"@. Instead of
11011128-- searching for the index of @\"::\"@ and taking the substrings
1102−-- before and after that index, you would instead use @splitTimes 1
1103−-- "::"@.
1129+-- before and after that index, you would instead use @find "::"@.
11041130
11051131-- | /O(n)/ 'Text' index (subscript) operator, starting from 0.
11061132index :: Text -> Int -> Char
tests/Properties.hs+1−17
@@ -399,24 +399,12 @@ t_tails = L.tails `eqP` (map unpackS . T.tails)
399399tl_tails = L.tails `eqP` (map unpackS . TL.tails)
400400
401401findSplit s t = case T.find s t of
402− (x,xs) -> x : L.map (T.drop (T.length s)) xs
402+ (x,xs) -> x : L.map (T.drop (T.length s) . fst) xs
403403
404404t_findSplit s = T.split s `eq` findSplit s
405405t_split_split s = T.split s `eq` Slow.split s
406406t_split_i (NotEmpty t) = id `eq` (T.intercalate t . T.split t)
407407tl_split_i (NotEmpty t) = id `eq` (TL.intercalate t . TL.split t)
408−t_splitTimes_i k (NotEmpty t) = id `eq` (T.intercalate t . T.splitTimes k t)
409−tl_splitTimes_i k (NotEmpty t) = id `eq` (TL.intercalate t . TL.splitTimes k t)
410−t_splitTimes_split k (NotEmpty t) =
411− T.splitTimes k t `eq` \u ->
412− case L.splitAt k (T.split t u) of
413− (a,[]) -> a
414− (a,b) -> a ++ [T.intercalate t b]
415−tl_splitTimes_split k (NotEmpty t) =
416− TL.splitTimes k t `eq` \u ->
417− case L.splitAt (fromIntegral k) (TL.split t u) of
418− (a,[]) -> a
419− (a,b) -> a ++ [TL.intercalate t b]
420408t_splitTimesEnd_i k (NotEmpty t) = id `eq` (T.intercalate t . T.splitTimesEnd k t)
421409tl_splitTimesEnd_i k (NotEmpty t) = id `eq` (TL.intercalate t . TL.splitTimesEnd k t)
422410t_splitTimesEnd_split (NotEmpty t) = T.splitTimesEnd maxBound t `eq` T.split t
@@ -798,10 +786,6 @@ tests = [
798786 testProperty "t_findSplit" t_findSplit,
799787 testProperty "t_split_split" t_split_split,
800788 testProperty "t_split_i" t_split_i,
801− testProperty "t_splitTimes_i" t_splitTimes_i,
802− testProperty "tl_splitTimes_i" tl_splitTimes_i,
803− testProperty "t_splitTimes_split" t_splitTimes_split,
804− testProperty "tl_splitTimes_split" tl_splitTimes_split,
805789 testProperty "t_splitTimesEnd_i" t_splitTimesEnd_i,
806790 testProperty "tl_splitTimesEnd_i" tl_splitTimesEnd_i,
807791 testProperty "t_splitTimesEnd_split" t_splitTimesEnd_split,