on master help sign in
Add a toTitle function

This fixes gh-38.

commit104c42256b718599f1b56bd8e2ceda6df44251a2 authorBryan O'Sullivan <bos@serpentine.com> dateSat 30 Nov 2013, 22:39 (13 years ago) parenta3ac323
3 files changed+84−2
Data/Text.hs+23 Data/Text/Fusion/Common.hs+37−2 Data/Text/Lazy.hs+24
Data/Text.hs+23
@@ -79,6 +79,7 @@ module Data.Text
7979 , toCaseFold
8080 , toLower
8181 , toUpper
82+ , toTitle
8283
8384 -- ** Justification
8485 , justifyLeft
@@ -679,6 +680,28 @@ toUpper :: Text -> Text
679680toUpper t = unstream (S.toUpper (stream t))
680681{-# INLINE toUpper #-}
681682
683+-- | /O(n)/ Convert a string to title case, using simple case
684+-- conversion.
685+--
686+-- Unlike the other case conversion functions, this function does not
687+-- convert every letter of its input. Instead, the first letter is
688+-- converted to title case, as is every subsequent letter that
689+-- immediately follows a non-letter.
690+--
691+-- The result string may be longer than the input string. For example,
692+-- the Latin small ligature &#xfb02; (U+FB02) is converted to the
693+-- sequence Latin capital letter F (U+0046) followed by Latin small
694+-- letter l (U+006C).
695+--
696+-- /Note/: this function does not take language or culture specific
697+-- rules into account. For instance, in English, different style
698+-- guides disagree on whether the book name \"The Hill of the Red
699+-- Fox\" is correctly title cased&#x2014;but this function will
700+-- capitalize /every/ word.
701+toTitle :: Text -> Text
702+toTitle t = unstream (S.toTitle (stream t))
703+{-# INLINE toTitle #-}
704+
682705-- | /O(n)/ Left-justify a string to the given length, using the
683706-- specified fill character on the right. Subject to fusion.
684707-- Performs replacement on invalid scalar values.
Data/Text/Fusion/Common.hs+37−2
@@ -42,6 +42,7 @@ module Data.Text.Fusion.Common
4242 -- $case
4343 , toCaseFold
4444 , toLower
45+ , toTitle
4546 , toUpper
4647
4748 -- ** Justification
@@ -102,13 +103,15 @@ module Data.Text.Fusion.Common
102103
103104import Prelude (Bool(..), Char, Eq(..), Int, Integral, Maybe(..),
104105 Ord(..), Ordering(..), String, (.), ($), (+), (-), (*), (++),
105− (&&), fromIntegral, otherwise)
106+ (&&), fromIntegral, not, otherwise)
106107import qualified Data.List as L
107108import qualified Prelude as P
108109import Data.Bits (shiftL)
110+import Data.Char (isLetter)
109111import Data.Int (Int64)
110112import Data.Text.Fusion.Internal
111−import Data.Text.Fusion.CaseMapping (foldMapping, lowerMapping, upperMapping)
113+import Data.Text.Fusion.CaseMapping (foldMapping, lowerMapping, titleMapping,
114+ upperMapping)
112115import Data.Text.Fusion.Size
113116import GHC.Prim (Addr#, chr#, indexCharOffAddr#, ord#)
114117import GHC.Types (Char(..), Int(..))
@@ -432,6 +435,38 @@ toLower :: Stream Char -> Stream Char
432435toLower = caseConvert lowerMapping
433436{-# INLINE [0] toLower #-}
434437
438+-- | /O(n)/ Convert a string to title case, using simple case
439+-- conversion.
440+--
441+-- Unlike the other case conversion functions, this function does not
442+-- convert every letter of its input. Instead, the first letter is
443+-- converted to title case, as is every subsequent letter that
444+-- immediately follows a non-letter.
445+--
446+-- The result string may be longer than the input string. For example,
447+-- the Latin small ligature &#xfb02; (U+FB02) is converted to the
448+-- sequence Latin capital letter F (U+0046) followed by Latin small
449+-- letter l (U+006C).
450+--
451+-- /Note/: this function does not take language or culture specific
452+-- rules into account. For instance, in English, different style
453+-- guides disagree on whether the book name \"The Hill of the Red
454+-- Fox\" is correctly title cased&#x2014;but this function will
455+-- capitalize /every/ word.
456+toTitle :: Stream Char -> Stream Char
457+toTitle (Stream next0 s0 len) = Stream next (CC (False :*: s0) '\0' '\0') len
458+ where
459+ next (CC (letter :*: s) '\0' _) =
460+ case next0 s of
461+ Done -> Done
462+ Skip s' -> Skip (CC (letter :*: s') '\0' '\0')
463+ Yield c s'
464+ | not letter && letter' -> titleMapping c (letter' :*: s')
465+ | otherwise -> Yield c (CC (letter' :*: s') '\0' '\0')
466+ where letter' = isLetter c
467+ next (CC s a b) = Yield a (CC s b '\0')
468+{-# INLINE [0] toTitle #-}
469+
435470justifyLeftI :: Integral a => a -> Char -> Stream Char -> Stream Char
436471justifyLeftI k c (Stream next0 s0 len) =
437472 Stream next (s0 :*: S1 :*: 0) (larger (fromIntegral k) len)
Data/Text/Lazy.hs+24
@@ -86,6 +86,7 @@ module Data.Text.Lazy
8686 , toCaseFold
8787 , toLower
8888 , toUpper
89+ , toTitle
8990
9091 -- ** Justification
9192 , justifyLeft
@@ -697,6 +698,29 @@ toUpper :: Text -> Text
697698toUpper t = unstream (S.toUpper (stream t))
698699{-# INLINE toUpper #-}
699700
701+
702+-- | /O(n)/ Convert a string to title case, using simple case
703+-- conversion.
704+--
705+-- Unlike the other case conversion functions, this function does not
706+-- convert every letter of its input. Instead, the first letter is
707+-- converted to title case, as is every subsequent letter that
708+-- immediately follows a non-letter.
709+--
710+-- The result string may be longer than the input string. For example,
711+-- the Latin small ligature &#xfb02; (U+FB02) is converted to the
712+-- sequence Latin capital letter F (U+0046) followed by Latin small
713+-- letter l (U+006C).
714+--
715+-- /Note/: this function does not take language or culture specific
716+-- rules into account. For instance, in English, different style
717+-- guides disagree on whether the book name \"The Hill of the Red
718+-- Fox\" is correctly title cased&#x2014;but this function will
719+-- capitalize /every/ word.
720+toTitle :: Text -> Text
721+toTitle t = unstream (S.toTitle (stream t))
722+{-# INLINE toTitle #-}
723+
700724-- | /O(n)/ 'foldl', applied to a binary operator, a starting value
701725-- (typically the left-identity of the operator), and a 'Text',
702726-- reduces the 'Text' using the binary operator, from left to right.