on master help sign in
Implement lazy find.

--HG-- extra : convert_revision : 4fa659b85d8ba56e173be38a2c7efa0fd19bc9f2

commit53fb88035a58d87acad26f6dff0c5e6891484aa3 authorBryan O'Sullivan <bos@serpentine.com> dateFri 9 Oct 2009, 05:38 (17 years ago) parentc16786c
3 files changed+46−2
Data/Text.hs+3 Data/Text/Lazy.hs+35 tests/Properties.hs+8−2
Data/Text.hs+3
@@ -1036,6 +1036,9 @@ break pat src@(Text arr off len)
10361036-- > ==> ("", [])
10371037-- > find "/" "a/b/c/d"
10381038-- > ==> ("a", [("/b","/b/c/d"), ("/c","/c/d"), ("/d","/d")])
1039+--
1040+-- In (unlikely) bad cases, this function's time complexity degrades
1041+-- towards /O(n*m)/.
10391042find :: Text -> Text -> (Text, [(Text, Text)])
10401043find pat src@(Text arr off len)
10411044 | null pat = emptyError "find"
Data/Text/Lazy.hs+35
@@ -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)
tests/Properties.hs+8−2
@@ -408,9 +408,14 @@ tl_inits = L.inits `eqP` (map unpackS . TL.inits)
408408t_tails = L.tails `eqP` (map unpackS . T.tails)
409409tl_tails = L.tails `eqP` (map unpackS . TL.tails)
410410
411−t_findSplit s = T.split s `eq` splitty
412− where splitty t = case T.find s t of
411+t_findSplit s t = (T.split s `eq` splitty) u
412+ where splitty v = case T.find s v of
413413 (x,xs) -> x : L.map (T.drop (T.length s) . fst) xs
414+ u = T.concat [t,s,t]
415+tl_findSplit s t = (TL.split s `eq` splitty) u
416+ where splitty v = case TL.find s v of
417+ (x,xs) -> x : L.map (TL.drop (TL.length s) . fst) xs
418+ u = TL.concat [t,s,t]
414419t_split_split s = unsquare ((T.split s `eq` Slow.split s) .
415420 T.intercalate s)
416421tl_split_split s = unsquare (((TL.split (chunkify s) . chunkify) `eq`
@@ -798,6 +803,7 @@ tests = [
798803
799804 testGroup "breaking many" [
800805 testProperty "t_findSplit" t_findSplit,
806+ testProperty "tl_findSplit" tl_findSplit,
801807 testProperty "t_split_split" t_split_split,
802808 testProperty "tl_split_split" tl_split_split,
803809 testProperty "t_split_i" t_split_i,