@@ -165,6 +165,7 @@ module Data.Text.Lazy
165165 -- ** View patterns
166166 , stripPrefix
167167 , stripSuffix
168+ , commonPrefixes
168169
169170 -- * Searching
170171 , filter
@@ -189,7 +190,7 @@ module Data.Text.Lazy
189190import Prelude (Char, Bool(..), Maybe(..), String,
190191 Eq(..), Ord(..), Ordering(..), Read(..), Show(..),
191192 (&&), (||), (+), (-), (.), ($), (++),
192− div, error, flip, fromIntegral, not, otherwise)
193+ div, error, flip, fmap, fromIntegral, not, otherwise)
193194import qualified Prelude as P
194195#if defined(HAVE_DEEPSEQ)
195196import Control.DeepSeq (NFData(..))
@@ -1325,51 +1326,77 @@ isInfixOf needle haystack
13251326-------------------------------------------------------------------------------
13261327-- * View patterns
13271328
1328−-- | /O(n)/ Returns the suffix of the second string if its prefix
1329−-- matches the first.
1329+-- | /O(n)/ Return the suffix of the second string if its prefix
1330+-- matches the entire first string.
13301331--
13311332-- Examples:
13321333--
13331334-- > stripPrefix "foo" "foobar" == Just "bar"
1335+-- > stripPrefix "" "baz" == Just "baz"
13341336-- > stripPrefix "foo" "quux" == Nothing
13351337--
13361338-- This is particularly useful with the @ViewPatterns@ extension to
13371339-- GHC, as follows:
13381340--
13391341-- > {-# LANGUAGE ViewPatterns #-}
1340−-- > import Data.Text as T
1342+-- > import Data.Text.Lazy as T
13411343-- >
13421344-- > fnordLength :: Text -> Int
13431345-- > fnordLength (stripPrefix "fnord" -> Just suf) = T.length suf
1344−-- > fnordLength _ = -1
1346+-- > fnordLength _ = -1
13451347stripPrefix :: Text -> Text -> Maybe Text
1346−-- Yes, this could be much more efficient.
13471348stripPrefix p t
1348− | p `isPrefixOf` t = Just (drop (length p) t)
1349− | otherwise = Nothing
1349+ | null p = Just t
1350+ | otherwise = case commonPrefixes p t of
1351+ Just (_,c,r) | null c -> Just r
1352+ _ -> Nothing
13501353
1351−-- | /O(n)/ Returns the prefix of the second string if its suffix
1352−-- matches the first.
1354+-- | /O(n)/ Find the longest non-empty common prefix of two strings
1355+-- and return it, along with the suffixes of each string at which they
1356+-- no longer match.
1357+--
1358+-- If the strings do not have a common prefix or either one is empty,
1359+-- this function returns 'Nothing'.
1360+--
1361+-- Examples:
1362+--
1363+-- > commonPrefixes "foobar" "fooquux" == Just ("foo","bar","quux")
1364+-- > commonPrefixes "veeble" "fetzer" == Nothing
1365+-- > commonPrefixes "" "baz" == Nothing
1366+commonPrefixes :: Text -> Text -> Maybe (Text,Text,Text)
1367+commonPrefixes Empty _ = Nothing
1368+commonPrefixes _ Empty = Nothing
1369+commonPrefixes a0 b0 = Just (go a0 b0 [])
1370+ where
1371+ go t0@(Chunk x xs) t1@(Chunk y ys) ps
1372+ = case T.commonPrefixes x y of
1373+ Just (p,a,b)
1374+ | T.null a -> go xs (chunk b ys) (p:ps)
1375+ | T.null b -> go (chunk a xs) ys (p:ps)
1376+ | otherwise -> (fromChunks (L.reverse (p:ps)),chunk a xs, chunk b ys)
1377+ Nothing -> (fromChunks (L.reverse ps),t0,t1)
1378+ go t0 t1 ps = (fromChunks (L.reverse ps),t0,t1)
1379+
1380+-- | /O(n)/ Return the prefix of the second string if its suffix
1381+-- matches the entire first string.
13531382--
13541383-- Examples:
13551384--
13561385-- > stripSuffix "bar" "foobar" == Just "foo"
1386+-- > stripSuffix "" "baz" == Just "baz"
13571387-- > stripSuffix "foo" "quux" == Nothing
13581388--
13591389-- This is particularly useful with the @ViewPatterns@ extension to
13601390-- GHC, as follows:
13611391--
13621392-- > {-# LANGUAGE ViewPatterns #-}
1363−-- > import Data.Text as T
1393+-- > import Data.Text.Lazy as T
13641394-- >
13651395-- > quuxLength :: Text -> Int
13661396-- > quuxLength (stripSuffix "quux" -> Just pre) = T.length pre
1367−-- > quuxLength _ = -1
1397+-- > quuxLength _ = -1
13681398stripSuffix :: Text -> Text -> Maybe Text
1369−-- Yes, this could be much more efficient.
1370−stripSuffix p t
1371− | p `isSuffixOf` t = Just (take (length t - length p) t)
1372− | otherwise = Nothing
1399+stripSuffix p t = reverse `fmap` stripPrefix (reverse p) (reverse t)
13731400
13741401-- | /O(n)/ 'filter', applied to a predicate and a 'Text',
13751402-- returns a 'Text' containing those characters that satisfy the