on master help sign in
Implement lazy find.
53fb880Bryan O'Sullivan
Data/Text.hs+3
@@ -1036,6 +1036,9 @@ break pat src@(Text arr off len)
1036-- > ==> ("", [])
1036-- > ==> ("", [])
1037-- > find "/" "a/b/c/d"
1037-- > find "/" "a/b/c/d"
1038-- > ==> ("a", [("/b","/b/c/d"), ("/c","/c/d"), ("/d","/d")])
1038-- > ==> ("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)/.
1039find :: Text -> Text -> (Text, [(Text, Text)])
1042find :: Text -> Text -> (Text, [(Text, Text)])
1040find pat src@(Text arr off len)
1043find pat src@(Text arr off len)
1041 | null pat = emptyError "find"
1044 | null pat = emptyError "find"
Data/Text/Lazy.hs+35
@@ -145,6 +145,7 @@ module Data.Text.Lazy
145
145
146 -- * Searching
146 -- * Searching
147 , filter
147 , filter
148+ , find
148 , findBy
149 , findBy
149 , partitionBy
150 , partitionBy
150
151
@@ -873,6 +874,40 @@ break pat src
873 (x:_) -> let h :*: t = splitAtWord x src
874 (x:_) -> let h :*: t = splitAtWord x src
874 in (h, t)
875 in (h, t)
875
876
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+
876-- | /O(n)/ 'breakBy' is like 'spanBy', but the prefix returned is over
911-- | /O(n)/ 'breakBy' is like 'spanBy', but the prefix returned is over
877-- elements that fail the predicate @p@.
912-- elements that fail the predicate @p@.
878breakBy :: (Char -> Bool) -> Text -> (Text, Text)
913breakBy :: (Char -> Bool) -> Text -> (Text, Text)
tests/Properties.hs+8−2
@@ -408,9 +408,14 @@ tl_inits = L.inits `eqP` (map unpackS . TL.inits)
408t_tails = L.tails `eqP` (map unpackS . T.tails)
408t_tails = L.tails `eqP` (map unpackS . T.tails)
409tl_tails = L.tails `eqP` (map unpackS . TL.tails)
409tl_tails = L.tails `eqP` (map unpackS . TL.tails)
410
410
411−t_findSplit s = T.split s `eq` splitty
411+t_findSplit s t = (T.split s `eq` splitty) u
412− where splitty t = case T.find s t of
412+ where splitty v = case T.find s v of
413 (x,xs) -> x : L.map (T.drop (T.length s) . fst) xs
413 (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]
414t_split_split s = unsquare ((T.split s `eq` Slow.split s) .
419t_split_split s = unsquare ((T.split s `eq` Slow.split s) .
415 T.intercalate s)
420 T.intercalate s)
416tl_split_split s = unsquare (((TL.split (chunkify s) . chunkify) `eq`
421tl_split_split s = unsquare (((TL.split (chunkify s) . chunkify) `eq`
@@ -798,6 +803,7 @@ tests = [
798
803
799 testGroup "breaking many" [
804 testGroup "breaking many" [
800 testProperty "t_findSplit" t_findSplit,
805 testProperty "t_findSplit" t_findSplit,
806+ testProperty "tl_findSplit" tl_findSplit,
801 testProperty "t_split_split" t_split_split,
807 testProperty "t_split_split" t_split_split,
802 testProperty "tl_split_split" tl_split_split,
808 testProperty "tl_split_split" tl_split_split,
803 testProperty "t_split_i" t_split_i,
809 testProperty "t_split_i" t_split_i,