@@ -145,6 +145,7 @@ module Data.Text.Lazy
145145
146146 -- * Searching
147147 , filter
148+ , find
148149 , findBy
149150 , partitionBy
150151
@@ -873,6 +874,40 @@ break pat src
873874 (x:_) -> let h :*: t = splitAtWord x src
874875 in (h, t)
875876
877+-- | /O(n+m)/ Find all non-overlapping instances of @needle@ in
878+-- @haystack@. The first element of the returned pair is the prefix
879+-- of @haystack@ prior to any matches of @needle@. The second is a
880+-- list of pairs.
881+--
882+-- The first element of each pair in the list is a span from the
883+-- beginning of a match to the beginning of the next match, while the
884+-- second is a span from the beginning of the match to the end of the
885+-- input.
886+--
887+-- Examples:
888+--
889+-- > find "::" ""
890+-- > ==> ("", [])
891+-- > find "/" "a/b/c/d"
892+-- > ==> ("a", [("/b","/b/c/d"), ("/c","/c/d"), ("/d","/d")])
893+--
894+-- This function is strict in its first argument, and lazy in its
895+-- second.
896+--
897+-- In (unlikely) bad cases, this function's time complexity degrades
898+-- towards /O(n*m)/.
899+find :: Text -> Text -> (Text, [(Text, Text)])
900+find pat src
901+ | null pat = emptyError "find"
902+ | otherwise = case indices pat src of
903+ [] -> (src, [])
904+ (x:xs) -> let h :*: t = splitAtWord x src
905+ in (h, go x xs t)
906+ where
907+ go !i (x:xs) cs = let h :*: t = splitAtWord (x-i) cs
908+ in (h, cs) : go x xs t
909+ go _ _ cs = [(cs,cs)]
910+
876911-- | /O(n)/ 'breakBy' is like 'spanBy', but the prefix returned is over
877912-- elements that fail the predicate @p@.
878913breakBy :: (Char -> Bool) -> Text -> (Text, Text)