@@ -15,7 +15,6 @@
1515--
1616-- License : BSD-style
1717-- Maintainer : bos@serpentine.com
18−-- Stability : experimental
1918-- Portability : GHC
2019--
2120-- A time and space-efficient implementation of Unicode text.
@@ -32,8 +31,9 @@
3231--
3332-- To use an extended and very rich family of functions for working
3433-- with Unicode text (including normalization, regular expressions,
35−-- non-standard encodings, text breaking, and locales), see
36−-- <http://hackage.haskell.org/package/text-icu the text-icu package >.
34+-- non-standard encodings, text breaking, and locales), see the
35+-- <http://hackage.haskell.org/package/text-icu text-icu package >.
36+--
3737
3838module Data.Text
3939 (
@@ -43,6 +43,9 @@ module Data.Text
4343 -- * Acceptable data
4444 -- $replacement
4545
46+ -- * Definition of character
47+ -- $character_definition
48+
4649 -- * Fusion
4750 -- $fusion
4851
@@ -60,6 +63,7 @@ module Data.Text
6063 , snoc
6164 , append
6265 , uncons
66+ , unsnoc
6367 , head
6468 , last
6569 , tail
@@ -298,6 +302,17 @@ unpackCString# addr# = Text $ SJS.unstream (SJS.streamCString# addr#)
298302 = singleton a #-}
299303
300304---------------------------------------------------------------------
305+-- $character_definition
306+--
307+-- This package uses the term /character/ to denote Unicode /code points/.
308+--
309+-- Note that this is not the same thing as a grapheme (e.g. a
310+-- composition of code points that form one visual symbol). For
311+-- instance, consider the grapheme \"ä\". This symbol has two
312+-- Unicode representations: a single code-point representation
313+-- @U+00E4@ (the @LATIN SMALL LETTER A WITH DIAERESIS@ code point),
314+-- and a two code point representation @U+0061@ (the \"@A@\" code
315+-- point) and @U+0308@ (the @COMBINING DIAERESIS@ code point).
301316
302317-- $strict
303318--
@@ -392,9 +407,13 @@ instance Read Text where
392407 readsPrec p str = [(pack x,y) | (x,y) <- readsPrec p str]
393408
394409#if MIN_VERSION_base(4,9,0)
395−-- Semigroup orphan instances for older GHCs are provided by
396−-- 'semigroups` package
397−
410+-- | Non-orphan 'Semigroup' instance only defined for
411+-- @base-4.9.0.0@ and later; orphan instances for older GHCs are
412+-- provided by
413+-- the [semigroups](http://hackage.haskell.org/package/semigroups)
414+-- package
415+--
416+-- @since 1.2.2.0
398417instance Semigroup Text where
399418 (<>) = append
400419#endif
@@ -412,6 +431,7 @@ instance IsString Text where
412431 fromString = pack
413432
414433#if __GLASGOW_HASKELL__ >= 708
434+-- | @since 1.2.0.0
415435instance Exts.IsList Text where
416436 type Item Text = Char
417437 fromList = pack
@@ -422,6 +442,7 @@ instance Exts.IsList Text where
422442instance NFData Text where rnf !_ = ()
423443#endif
424444
445+-- | @since 1.2.1.0
425446instance Binary Text where
426447 put t = put (encodeUtf8 t)
427448 get = do
@@ -455,6 +476,8 @@ instance Data Text where
455476
456477#if MIN_VERSION_base(4,7,0)
457478-- | Only defined for @base-4.7.0.0@ and later
479+--
480+-- @since 1.2.2.0
458481instance PrintfArg Text where
459482 formatArg t = formatString $ unpack t
460483#endif
@@ -612,6 +635,19 @@ init = coerce JSS.init
612635 unstream (S.init (stream t)) = init t
613636 #-}
614637
638+-- | /O(1)/ Returns all but the last character and the last character of a
639+-- 'Text', or 'Nothing' if empty.
640+--
641+-- @since 1.2.3.0
642+unsnoc :: Text -> Maybe (Text, Char)
643+unsnoc (Text arr off len)
644+ | len <= 0 = Nothing
645+ | n < 0xDC00 || n > 0xDFFF = Just (text arr off (len-1), unsafeChr n)
646+ | otherwise = Just (text arr off (len-2), U16.chr2 n0 n)
647+ where n = A.unsafeIndex arr (off+len-1)
648+ n0 = A.unsafeIndex arr (off+len-2)
649+{-# INLINE [1] unsnoc #-}
650+
615651-- | /O(1)/ Tests whether a 'Text' is empty or not. Subject to
616652-- fusion.
617653null :: Text -> Bool
@@ -693,8 +729,15 @@ compareLength t n = S.compareLengthI (stream t) n
693729-- -----------------------------------------------------------------------------
694730-- * Transformations
695731-- | /O(n)/ 'map' @f@ @t@ is the 'Text' obtained by applying @f@ to
696−-- each element of @t@. Subject to fusion. Performs replacement on
697−-- invalid scalar values.
732+-- each element of @t@.
733+--
734+-- Example:
735+--
736+-- >>> let message = pack "I am not angry. Not at all."
737+-- >>> T.map (\c -> if c == '.' then '!' else c) message
738+-- "I am not angry! Not at all!"
739+--
740+-- Subject to fusion. Performs replacement on invalid scalar values.
698741map :: (Char -> Char) -> Text -> Text
699742map = coerce JSS.map
700743-- map f t = unstream (S.map (safe . f) (stream t))
@@ -703,20 +746,38 @@ map = coerce JSS.map
703746-- | /O(n)/ The 'intercalate' function takes a 'Text' and a list of
704747-- 'Text's and concatenates the list after interspersing the first
705748-- argument between each element of the list.
749+--
750+-- Example:
751+--
752+-- >>> T.intercalate "NI!" ["We", "seek", "the", "Holy", "Grail"]
753+-- "WeNI!seekNI!theNI!HolyNI!Grail"
706754intercalate :: Text -> [Text] -> Text
707755intercalate = coerce JSS.intercalate
708756-- intercalate t = concat . (F.intersperse t)
709757{-# INLINE intercalate #-}
710758
711759-- | /O(n)/ The 'intersperse' function takes a character and places it
712−-- between the characters of a 'Text'. Subject to fusion. Performs
713−-- replacement on invalid scalar values.
760+-- between the characters of a 'Text'.
761+--
762+-- Example:
763+--
764+-- >>> T.intersperse '.' "SHIELD"
765+-- "S.H.I.E.L.D"
766+--
767+-- Subject to fusion. Performs replacement on invalid scalar values.
714768intersperse :: Char -> Text -> Text
715769intersperse = coerce JSS.intersperse
716770-- intersperse c t = unstream (S.intersperse (safe c) (stream t))
717771{-# INLINE intersperse #-}
718772
719−-- | /O(n)/ Reverse the characters of a string. Subject to fusion.
773+-- | /O(n)/ Reverse the characters of a string.
774+--
775+-- Example:
776+--
777+-- >>> T.reverse "desrever"
778+-- "reversed"
779+--
780+-- Subject to fusion.
720781reverse :: Text -> Text
721782reverse = coerce JSS.reverse
722783-- reverse t = S.reverse (stream t)
@@ -736,12 +797,14 @@ reverse = coerce JSS.reverse
736797-- @needle@ occurs in @replacement@, that occurrence will /not/ itself
737798-- be replaced recursively:
738799--
739−-- > replace "oo" "foo" "oo" == "foo"
800+-- >>> replace "oo" "foo" "oo"
801+-- "foo"
740802--
741803-- In cases where several instances of @needle@ overlap, only the
742804-- first one will be replaced:
743805--
744−-- > replace "ofo" "bar" "ofofo" == "barfo"
806+-- >>> replace "ofo" "bar" "ofofo"
807+-- "barfo"
745808--
746809-- In (unlikely) bad cases, this function's time complexity degrades
747810-- towards /O(n*m)/.
@@ -859,6 +922,8 @@ toUpper = coerce JSS.toUpper
859922-- guides disagree on whether the book name \"The Hill of the Red
860923-- Fox\" is correctly title cased—but this function will
861924-- capitalize /every/ word.
925+--
926+-- @since 1.0.0.0
862927toTitle :: Text -> Text
863928toTitle = coerce JSS.toTitle
864929-- toTitle t = unstream (S.toTitle (stream t))
@@ -870,8 +935,11 @@ toTitle = coerce JSS.toTitle
870935--
871936-- Examples:
872937--
873−-- > justifyLeft 7 'x' "foo" == "fooxxxx"
874−-- > justifyLeft 3 'x' "foobar" == "foobar"
938+-- >>> justifyLeft 7 'x' "foo"
939+-- "fooxxxx"
940+--
941+-- >>> justifyLeft 3 'x' "foobar"
942+-- "foobar"
875943justifyLeft :: Int -> Char -> Text -> Text
876944justifyLeft = coerce JSS.justifyLeft
877945-- justifyLeft k c t
@@ -893,8 +961,11 @@ justifyLeft = coerce JSS.justifyLeft
893961--
894962-- Examples:
895963--
896−-- > justifyRight 7 'x' "bar" == "xxxxbar"
897−-- > justifyRight 3 'x' "foobar" == "foobar"
964+-- >>> justifyRight 7 'x' "bar"
965+-- "xxxxbar"
966+--
967+-- >>> justifyRight 3 'x' "foobar"
968+-- "foobar"
898969justifyRight :: Int -> Char -> Text -> Text
899970justifyRight = coerce JSS.justifyRight
900971-- justifyRight k c t
@@ -909,7 +980,8 @@ justifyRight = coerce JSS.justifyRight
909980--
910981-- Examples:
911982--
912−-- > center 8 'x' "HS" = "xxxHSxxx"
983+-- >>> center 8 'x' "HS"
984+-- "xxxHSxxx"
913985center :: Int -> Char -> Text -> Text
914986center = coerce JSS.center
915987-- center k c t
@@ -925,6 +997,14 @@ center = coerce JSS.center
925997-- of its 'Text' argument. Note that this function uses 'pack',
926998-- 'unpack', and the list version of transpose, and is thus not very
927999-- efficient.
1000+--
1001+-- Examples:
1002+--
1003+-- >>> transpose ["green","orange"]
1004+-- ["go","rr","ea","en","ng","e"]
1005+--
1006+-- >>> transpose ["blue","red"]
1007+-- ["br","le","ud","e"]
9281008transpose :: [Text] -> [Text]
9291009transpose = coerce JSS.transpose
9301010-- transpose ts = P.map pack (L.transpose (P.map unpack ts))
@@ -1207,7 +1287,10 @@ take = coerce JSS.take
12071287--
12081288-- Examples:
12091289--
1210−-- > takeEnd 3 "foobar" == "bar"
1290+-- >>> takeEnd 3 "foobar"
1291+-- "bar"
1292+--
1293+-- @since 1.1.1.0
12111294takeEnd :: Int -> Text -> Text
12121295takeEnd = coerce JSS.takeEnd
12131296-- takeEnd n t@(Text arr off len)
@@ -1248,7 +1331,10 @@ drop = coerce JSS.drop
12481331--
12491332-- Examples:
12501333--
1251−-- > dropEnd 3 "foobar" == "foo"
1334+-- >>> dropEnd 3 "foobar"
1335+-- "foo"
1336+--
1337+-- @since 1.1.1.0
12521338dropEnd :: Int -> Text -> Text
12531339dropEnd = coerce JSS.dropEnd
12541340-- dropEnd n t@(Text arr off len)
@@ -1280,7 +1366,10 @@ takeWhile = coerce JSS.takeWhile
12801366-- satisfy @p@. Subject to fusion.
12811367-- Examples:
12821368--
1283−-- > takeWhileEnd (=='o') "foo" == "oo"
1369+-- >>> takeWhileEnd (=='o') "foo"
1370+-- "oo"
1371+--
1372+-- @since 1.2.2.0
12841373takeWhileEnd :: (Char -> Bool) -> Text -> Text
12851374#ifndef __GHCJS__
12861375takeWhileEnd p t@(Text arr off len) = loop (len-1) len
@@ -1329,7 +1418,8 @@ dropWhile = coerce JSS.dropWhile
13291418--
13301419-- Examples:
13311420--
1332−-- > dropWhileEnd (=='.') "foo..." == "foo"
1421+-- >>> dropWhileEnd (=='.') "foo..."
1422+-- "foo"
13331423dropWhileEnd :: (Char -> Bool) -> Text -> Text
13341424dropWhileEnd = coerce JSS.dropWhileEnd
13351425-- dropWhileEnd p t@(Text arr off len) = loop (len-1) len
@@ -1454,9 +1544,14 @@ tails = coerce JSS.tails
14541544--
14551545-- Examples:
14561546--
1457−-- > splitOn "\r\n" "a\r\nb\r\nd\r\ne" == ["a","b","d","e"]
1458−-- > splitOn "aaa" "aaaXaaaXaaaXaaa" == ["","X","X","X",""]
1459−-- > splitOn "x" "x" == ["",""]
1547+-- >>> splitOn "\r\n" "a\r\nb\r\nd\r\ne"
1548+-- ["a","b","d","e"]
1549+--
1550+-- >>> splitOn "aaa" "aaaXaaaXaaaXaaa"
1551+-- ["","X","X","X",""]
1552+--
1553+-- >>> splitOn "x" "x"
1554+-- ["",""]
14601555--
14611556-- and
14621557--
@@ -1493,8 +1588,11 @@ splitOn = coerce JSS.splitOn
14931588-- resulting components do not contain the separators. Two adjacent
14941589-- separators result in an empty component in the output. eg.
14951590--
1496−-- > split (=='a') "aabbaca" == ["","","bb","c",""]
1497−-- > split (=='a') "" == [""]
1591+-- >>> split (=='a') "aabbaca"
1592+-- ["","","bb","c",""]
1593+--
1594+-- >>> split (=='a') ""
1595+-- [""]
14981596split :: (Char -> Bool) -> Text -> [Text]
14991597split = coerce JSS.split
15001598-- split _ t@(Text _off _arr 0) = [t]
@@ -1508,8 +1606,11 @@ split = coerce JSS.split
15081606-- element may be shorter than the other chunks, depending on the
15091607-- length of the input. Examples:
15101608--
1511−-- > chunksOf 3 "foobarbaz" == ["foo","bar","baz"]
1512−-- > chunksOf 4 "haskell.org" == ["hask","ell.","org"]
1609+-- >>> chunksOf 3 "foobarbaz"
1610+-- ["foo","bar","baz"]
1611+--
1612+-- >>> chunksOf 4 "haskell.org"
1613+-- ["hask","ell.","org"]
15131614chunksOf :: Int -> Text -> [Text]
15141615chunksOf = coerce JSS.chunksOf
15151616-- chunksOf k = go
@@ -1558,8 +1659,11 @@ filter = coerce JSS.filter
15581659--
15591660-- Examples:
15601661--
1561−-- > breakOn "::" "a::b::c" ==> ("a", "::b::c")
1562−-- > breakOn "/" "foobar" ==> ("foobar", "")
1662+-- >>> breakOn "::" "a::b::c"
1663+-- ("a","::b::c")
1664+--
1665+-- >>> breakOn "/" "foobar"
1666+-- ("foobar","")
15631667--
15641668-- Laws:
15651669--
@@ -1588,7 +1692,8 @@ breakOn = coerce JSS.breakOn
15881692-- up to and including the last match of @needle@. The second is the
15891693-- remainder of @haystack@, following the match.
15901694--
1591−-- > breakOnEnd "::" "a::b::c" ==> ("a::b::", "c")
1695+-- >>> breakOnEnd "::" "a::b::c"
1696+-- ("a::b::","c")
15921697breakOnEnd :: Text -> Text -> (Text, Text)
15931698breakOnEnd = coerce JSS.breakOnEnd
15941699-- breakOnEnd pat src = (reverse b, reverse a)
@@ -1604,10 +1709,11 @@ breakOnEnd = coerce JSS.breakOnEnd
16041709--
16051710-- Examples:
16061711--
1607−-- > breakOnAll "::" ""
1608−-- > ==> []
1609−-- > breakOnAll "/" "a/b/c/"
1610−-- > ==> [("a", "/b/c/"), ("a/b", "/c/"), ("a/b/c", "/")]
1712+-- >>> breakOnAll "::" ""
1713+-- []
1714+--
1715+-- >>> breakOnAll "/" "a/b/c/"
1716+-- [("a","/b/c/"),("a/b","/c/"),("a/b/c","/")]
16111717--
16121718-- In (unlikely) bad cases, this function's time complexity degrades
16131719-- towards /O(n*m)/.
@@ -1821,9 +1927,14 @@ isInfixOf = coerce JSS.isInfixOf
18211927--
18221928-- Examples:
18231929--
1824−-- > stripPrefix "foo" "foobar" == Just "bar"
1825−-- > stripPrefix "" "baz" == Just "baz"
1826−-- > stripPrefix "foo" "quux" == Nothing
1930+-- >>> stripPrefix "foo" "foobar"
1931+-- Just "bar"
1932+--
1933+-- >>> stripPrefix "" "baz"
1934+-- Just "baz"
1935+--
1936+-- >>> stripPrefix "foo" "quux"
1937+-- Nothing
18271938--
18281939-- This is particularly useful with the @ViewPatterns@ extension to
18291940-- GHC, as follows:
@@ -1849,9 +1960,14 @@ stripPrefix = coerce JSS.stripPrefix
18491960--
18501961-- Examples:
18511962--
1852−-- > commonPrefixes "foobar" "fooquux" == Just ("foo","bar","quux")
1853−-- > commonPrefixes "veeble" "fetzer" == Nothing
1854−-- > commonPrefixes "" "baz" == Nothing
1963+-- >>> commonPrefixes "foobar" "fooquux"
1964+-- Just ("foo","bar","quux")
1965+--
1966+-- >>> commonPrefixes "veeble" "fetzer"
1967+-- Nothing
1968+--
1969+-- >>> commonPrefixes "" "baz"
1970+-- Nothing
18551971commonPrefixes :: Text -> Text -> Maybe (Text,Text,Text)
18561972commonPrefixes = coerce JSS.commonPrefixes
18571973-- commonPrefixes t0@(Text arr0 off0 len0) t1@(Text arr1 off1 len1) = go 0 0
@@ -1869,9 +1985,14 @@ commonPrefixes = coerce JSS.commonPrefixes
18691985--
18701986-- Examples:
18711987--
1872−-- > stripSuffix "bar" "foobar" == Just "foo"
1873−-- > stripSuffix "" "baz" == Just "baz"
1874−-- > stripSuffix "foo" "quux" == Nothing
1988+-- >>> stripSuffix "bar" "foobar"
1989+-- Just "foo"
1990+--
1991+-- >>> stripSuffix "" "baz"
1992+-- Just "baz"
1993+--
1994+-- >>> stripSuffix "foo" "quux"
1995+-- Nothing
18751996--
18761997-- This is particularly useful with the @ViewPatterns@ extension to
18771998-- GHC, as follows:
@@ -1923,3 +2044,11 @@ foreign import javascript unsafe
19232044 "h$jsstringReplicateChar" js_replicateChar :: Int -> Char -> JSString
19242045foreign import javascript unsafe
19252046 "$2.substr($1)" js_substr1 :: Int -> JSString -> JSString
2047+
2048+-------------------------------------------------
2049+-- NOTE: the named chunk below used by doctest;
2050+-- verify the doctests via `doctest -fobject-code Data/Text.hs`
2051+
2052+-- $setup
2053+-- >>> :set -XOverloadedStrings
2054+-- >>> import qualified Data.Text as T