on master help sign in
Add portable line splitter.

--HG-- extra : convert_revision : 89ec748450fd9266f88d75937f8dbf520c4cfddb

commit1eac48f7f84a17345ad0396e2afbb4251537b6be authorBryan O'Sullivan <bos@serpentine.com> dateMon 23 Feb 2009, 00:21 (18 years ago) parentdf71ecc
2 files changed+36−8
Data/Text.hs+27−8 tests/Properties.hs+9
Data/Text.hs+27−8
@@ -110,6 +110,7 @@ module Data.Text
110110
111111 -- ** Breaking into lines and words
112112 , lines
113+ , lines'
113114 , words
114115 , unlines
115116 , unwords
@@ -143,7 +144,7 @@ module Data.Text
143144 ) where
144145
145146import Prelude (Char, Bool(..), Functor(..), Int, Maybe(..), String,
146− Eq, (==), (++),
147+ Eq(..), (++),
147148 Read(..), Show(..),
148149 (&&), (||), (+), (-), (<), (>), (<=), (>=), (.), ($),
149150 not, return, otherwise)
@@ -904,16 +905,34 @@ words t@(Text arr off len) = loop 0 0
904905
905906-- | /O(n)/ Breaks a 'Text' up into a list of 'Text's at
906907-- newline 'Char's. The resulting strings do not contain newlines.
907−--
908908lines :: Text -> [Text]
909−lines ps
910− | null ps = []
911− | otherwise = case search ps of
912− Nothing -> [ps]
913− Just n -> take n ps : lines (drop (n+1) ps)
914− where search = elemIndex '\n'
909+lines ps | null ps = []
910+ | otherwise = h : if null t
911+ then []
912+ else lines (unsafeTail t)
913+ where (h,t) = span (/= '\n') ps
915914{-# INLINE lines #-}
916915
916+-- | /O(n)/ Portably breaks a 'Text' up into a list of 'Text's at line
917+-- boundaries.
918+--
919+-- A line boundary is considered to be either a line feed, a carriage
920+-- return immediately followed by a line feed, or a carriage return.
921+-- This accounts for both Unix and Windows line ending conventions,
922+-- and for the old convention used on Mac OS 9 and earlier.
923+lines' :: Text -> [Text]
924+lines' ps | null ps = []
925+ | otherwise = h : case uncons t of
926+ Nothing -> []
927+ Just (c,t')
928+ | c == '\n' -> lines t'
929+ | c == '\r' -> case uncons t' of
930+ Just ('\n',t'') -> lines t''
931+ _ -> lines t'
932+ where (h,t) = span notEOL ps
933+ notEOL c = c /= '\n' && c /= '\r'
934+{-# INLINE lines' #-}
935+
917936-- | /O(n)/ Joins lines, after appending a terminating newline to
918937-- each.
919938unlines :: [Text] -> Text
tests/Properties.hs+9
@@ -153,6 +153,14 @@ prop_breakSubstringC c
153153 (unpack2 . T.breakSubstring (T.singleton c))
154154
155155prop_lines = L.lines `eqP` (map unpack . T.lines)
156+prop_lines' = lines' `eqP` (map unpack . T.lines')
157+ where lines' "" = []
158+ lines' s = let (l, s') = break eol s
159+ in l : case s' of
160+ [] -> []
161+ ('\r':'\n':s'') -> lines' s''
162+ (_:s'') -> lines' s''
163+ eol c = c == '\r' || c == '\n'
156164prop_words = L.words `eqP` (map unpack . T.words)
157165prop_unlines = L.unlines `eq` (unpack . T.unlines . map pack)
158166prop_unwords = L.unwords `eq` (unpack . T.unwords . map pack)
@@ -272,6 +280,7 @@ tests = [
272280 ("prop_breakSubstring_isInfixOf", mytest prop_breakSubstring_isInfixOf),
273281
274282 ("prop_lines", mytest prop_lines),
283+ ("prop_lines'", mytest prop_lines'),
275284 ("prop_words", mytest prop_words),
276285 ("prop_unlines", mytest prop_unlines),
277286 ("prop_unwords", mytest prop_unwords),