@@ -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