strings (empty) → 1.0.0
raw patch · 4 files changed
+673/−0 lines, 4 filesdep +basedep +bytestringdep +textsetup-changed
Dependencies added: base, bytestring, text
Files
- LICENSE +18/−0
- Setup.lhs +4/−0
- src/Data/Strings.hs +633/−0
- strings.cabal +18/−0
+ LICENSE view
@@ -0,0 +1,18 @@+Permission is hereby granted, free of charge, to any person obtaining+a copy of this software and associated documentation files (the "Software"),+to deal in the Software without restriction, including without limitation+the rights to use, copy, modify, merge, publish, distribute, sublicense,+and/or sell copies of the Software, and to permit persons to whom the+Software is furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included+in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER+DEALINGS IN THE SOFTWARE.+
+ Setup.lhs view
@@ -0,0 +1,4 @@+import Distribution.Simple++main = defaultMain+
+ src/Data/Strings.hs view
@@ -0,0 +1,633 @@+{-# LANGUAGE TypeSynonymInstances,+ FlexibleInstances,+ Trustworthy #-}++-- | Functions for working with strings, including 'Text', 'ByteString', etc.+--+-- This module aims at offering a consistent interface across all the available+-- string types. It currently offers instances for the ordinary Haskell 'String'+-- type, 'Text', lazy 'LazyT.Text', 'ByteString', and lazy 'LazyB.ByteString'.+--+-- If especially provides functions for some types, which are otherwise not+-- available nativly (such as 'breakOnSubstring' is not available for the lazy+-- 'LazyT.Text' type, is offered by 'sBreak' and 'strBreak').+module Data.Strings (++ text,+ lazyText,+ bytes,+ lazyBytes,++ Str (..),+ Strings (..)++) where+++import Data.Int+import Data.Word+import Data.String hiding (fromString)+import qualified Data.String as S+import qualified Data.Char as C++import qualified Data.ByteString.Char8 as B8+import qualified Data.ByteString as B+import Data.ByteString (ByteString)+import qualified Data.ByteString.Lazy.Char8 as LazyB8+import qualified Data.ByteString.Lazy as LazyB+import qualified Data.Text as T+import Data.Text (Text)+import qualified Data.Text.Lazy as LazyT+import qualified Data.List as L+import qualified Data.Text.Encoding as Enc+import qualified Data.Text.Lazy.Encoding as LazyEnc++-- | Returns @True@ exactly for space (0x20), and horizontal tab (0x09).+isSpace x+ | x == ' ' = True+ | x == '\t' = True+ | otherwise = False++-- | Returns @True@ exactly for space (0x20), horizontal tab (0x09), carriage return (0x0D), and line feed (0x0A).+isWhiteSpace x+ | x == ' ' = True+ | x == '\t' = True+ | x == '\r' = True+ | x == '\n' = True+ | otherwise = False+++-- | Create a 'Text' object form an ordinary Haskell 'String'.+text :: String -> Text+text = S.fromString++-- | Create a lazy 'LazyT.Text' object from an ordinary Haskell 'String'.+lazyText :: String -> LazyT.Text+lazyText = S.fromString++-- | Create a 'ByteString' object form an ordinary Haskell 'String'.+-- This function will encode a String using the UTF-8 character encoding.+bytes :: String -> ByteString+bytes = sFromUnicodeString++-- | Create a lazy 'LazyB.ByteString' object from an ordinary Haskell 'String'.+-- This function will encode a String using the UTF-8 character encoding.+lazyBytes :: String -> LazyB.ByteString+lazyBytes = sFromUnicodeString++-- | The 'Str' class provides functions for working with arbitrary Strings.+-- It is basically the same interface as provided by the 'Strings' class.+-- However, every input string is a Haskell String here, thus easing the+-- usage of different string types with native Haskell String literals.+--+-- For example @strAppend "suffix"@ works with any string type for which+-- an instance of @Str@ is defined. In order to maximize the ease of use+-- of this library, the functions are prefixed with @str@.+--+-- The complexity and efficiency of these functions depends on the underlying+-- string type being used.+class (Eq a, Strings a) => Str a where++ -- | Check whether the given string is empty or not. 'null' generalised.+ strNull :: a -> Bool++ -- | 'length' generalised.+ strLen :: a -> Int++ -- | 'head' generalised. This function is undefined if 'strNull' would return @True@.+ strHead :: a -> Char++ -- | 'last' generalised. This function is undefined if 'strNull' would return @True@.+ strLast :: a -> Char++ -- | 'init' generalised. This function is undefined if 'strNull' would return @True@.+ strInit :: a -> a++ -- | 'tail' generalised. This function is undefined if 'strNull' would return @True@.+ strTail :: a -> a++ -- | 'take' generalised.+ strTake :: Int -> a -> a++ -- | 'drop' generalised.+ strDrop :: Int -> a -> a+ + -- | Replace a substring with another string.+ strReplace :: String -- ^ Needle.+ -> String -- ^ Replacement.+ -> a -- ^ Haystack.+ -> a -- ^ Result: @Haystack@ with @Needle@ replaced by @Replacement@.++ -- | Breaks the string on the first occurence of the given substring.+ --+ -- > strBreak "xx" "1x2xx3xx4" = ("1x2", "xx3xx4")+ strBreak :: String -> a -> (a, a)++ -- | Like 'strBreak', but the string to break on is excluded from the result.+ --+ -- > strSplit "xx" "1x2xx3xx4" = ("1x2", "3xx4")+ strSplit :: String -> a -> (a, a)++ -- | Split a string into multiple fragments, separated by the given substring.+ --+ -- > strSplitAll "xx" "1x2xx3xx4" = ["1x2", "3", "4"]+ strSplitAll :: String -> a -> [a]++ -- | @concat@ generalised.+ strConcat :: [a] -> a++ -- | Glue together multiple strings by a given Haskell 'String'.+ --+ -- > strJoin x = concat . intersperse x+ strJoin :: String -> [a] -> a++ -- | Appends the given Haskell 'String' to the string. @++@ generalised.+ --+ -- > strAppend " world" "hello" = "hello world"+ strAppend :: String -- The String to append.+ -> a -- The string to append to.+ -> a -- The concatenation of the two strings.++ -- | Strips white space characters off both ends of the string.+ strTrim :: a -> a++ -- | Appends the given character n times to the left, such that+ -- the resulting string has the given length.+ --+ -- > strPadLeft '0' 8 "4711" == "00004711"+ strPadLeft :: Char -> Int -> a -> a++ -- | Appends the given character n times to the right, such that+ -- the resulting string has the given length.+ --+ -- > strPadRight '0' 8 "4711" == "47110000"+ strPadRight :: Char -> Int -> a -> a++ -- | Appends the given character n times to both sides, such that+ -- the resulting string has the given length.+ --+ -- > strPadBoth '0' 8 "4711" == "00471100"+ strPadBoth :: Char -> Int -> a -> a++ -- | Reverse the string.+ strReverse :: a -> a++ -- | Check if the given Haskell String equals the string.+ strEq :: String -- ^ The Haskell String.+ -> a -- ^ The string.+ -> Bool -- @True@ iff @fromString haskellString == string@++ -- | Check if the string starts with the given Haskell String.+ strStartsWith :: a -> String -> Bool++ -- | Check if the string ends with the given Haskell String.+ strEndsWith :: a -> String -> Bool++ -- | Create a string from a Haskell String.+ fromString :: String -> a++ -- | Create a string from a Haskell String. If the string does not support unicode,+ -- the Haskell String is encoded using UTF-8.+ fromUnicodeString :: String -> a++ -- | Convert the string into a Haskell String.+ toString :: a -> String++ -- | Convert the string into a list of bytes.+ toWord8 :: a -> [Word8]++ strNull = sNull+ strLen = sLen++ strHead = sHead+ strLast = sLast++ strInit = sInit+ strTail = sTail+ strTake = sTake+ strDrop = sDrop++ strReplace n r = sReplace (fromString n) (fromString r)++ strBreak n = sBreak (fromString n)+ strSplit d s = (a, b)+ where (a, b, _) = sSplit (fromString d) s+ strSplitAll n = sSplitAll (fromString n)++ strConcat = sConcat+ strJoin d = let d' = fromUnicodeString d in strConcat . L.intersperse d'+ strAppend x xs = sConcat [xs, fromString x]+ strTrim = sTrim++ strPadLeft = sPadLeft+ strPadRight = sPadRight+ strPadBoth = sPadBoth++ strReverse = sReverse++ strStartsWith s pref = sStartsWith s (fromString pref)+ strEndsWith s suff = sEndsWith s (fromString suff)++ strEq s1 s2 = fromUnicodeString s1 == s2++ fromString = sFromString+ fromUnicodeString = sFromUnicodeString++ toString = sToString+ toWord8 = sToWord8++{-+instance IsString Data.ByteString.ByteString where+ fromString = Enc.encodeUtf8 . Data.Text.pack++instance IsString Data.ByteString.Lazy.ByteString where+ fromString = LazyEnc.encodeUtf8 . Data.Text.Lazy.pack+-}++instance Str Text where+instance Str LazyT.Text where+instance Str ByteString where+instance Str LazyB.ByteString where+instance Str String where++-- | The goal of this class is to offer the same interface for various+-- types of strings ('ByteString', 'Text', Haskell 'String', etc.).+-- If a certain type offers a native implementation for a given function,+-- 'Strings' uses it. If not, a default implementation is given.+--+-- All of these functions are prefixed with @s@ to avoid nameclashes+-- with existing functions from the prelude.+--+-- The complexity and efficiency of these functions depends on the underlying+-- string type being used.+class Strings a where++ -- | Check whether the given string is empty or not. @null@ generalised.+ sNull :: a -> Bool++ -- | The empty string.+ sEmpty :: a++ -- | 'length' generalised.+ sLen :: a -> Int++ -- | 'head' generalised. This function is undefined if 'strNull' would return @True@.+ sHead :: a -> Char++ -- | 'last' generalised. This function is undefined if 'strNull' would return @True@.+ sLast :: a -> Char++ -- | 'init' generalised. This function is undefined if 'strNull' would return @True@.+ sInit :: a -> a++ -- | 'tail' generalised. This function is undefined if 'strNull' would return @True@.+ sTail :: a -> a++ -- | 'take' generalised.+ sTake :: Int -> a -> a++ -- | 'drop' generalised.+ sDrop :: Int -> a -> a++ -- | 'takeWhile' generalised.+ sTakeWhile :: (Char -> Bool) -> a -> a++ -- | 'dropWhile' generalised.+ sDropWhile :: (Char -> Bool) -> a -> a++ -- | Replace a substring with another string.+ sReplace :: a -> a -> a -> a++ -- | Breaks the string on the first occurence of the given substring.+ --+ -- > strBreak "xx" "1x2xx3xx4" = ("1x2", "xx3xx4")+ sBreak :: a -> a -> (a, a)++ -- | Like 'sBreak', but the string to break on is excluded from the result.+ --+ -- > strSplit "xx" "1x2xx3xx4" = ("1x2", "3xx4")+ sSplit :: a -> a -> (a, a, Bool)++ -- | Split a string into multiple fragments, separated by the given substring.+ --+ -- > strSplitAll "xx" "1x2xx3xx4" = ["1x2", "3", "4"]+ sSplitAll :: a -> a -> [a]++ -- | Check if the string starts with the given string.+ sStartsWith :: a -> a -> Bool++ -- | Check if the string ends with the given string.+ sEndsWith :: a -> a -> Bool++ -- | Concatenate all the strings in the list to a single string.+ sConcat :: [a] -> a++ -- | Strips white space characters off both ends of the string.+ sTrim :: a -> a++ -- | Appends the given character n times to the left, such that+ -- the resulting string has the given length.+ --+ -- > strPadLeft '0' 8 "4711" == "00004711"+ sPadLeft :: Char -> Int -> a -> a++ -- | Appends the given character n times to the right, such that+ -- the resulting string has the given length.+ --+ -- > strPadRight '0' 8 "4711" == "47110000"+ sPadRight :: Char -> Int -> a -> a++ -- | Appends the given character n times to both sides, such that+ -- the resulting string has the given length.+ --+ -- > strPadBoth '0' 8 "4711" == "00471100"+ sPadBoth :: Char -> Int -> a -> a++ -- 'reverse' the string.+ sReverse :: a -> a++ -- | Create a string from a Haskell String.+ sFromString :: String -> a++ -- | Create a string from a Haskell String. If the string does not support unicode,+ -- the Haskell String is encoded using UTF-8.+ sFromUnicodeString :: String -> a++ -- | Convert the string into a Haskell String.+ sToString :: a -> String++ -- | Convert the string into a list of bytes.+ sToWord8 :: a -> [Word8]++ sBreak d src = search 0 src+ where+ search a b | a `seq` b `seq` False = undefined+ search n s+ | sNull s = (src, sEmpty)+ | sStartsWith s d = (sTake n src, s)+ | otherwise = search (n+1) (sTail s)++ sReplace n r = sConcat . replace n r+ where+ replace n r h = if sNull b+ then (if c then [a, r] else [a])+ else a : r : replace n r b+ where (a, b, c) = sSplit n h++ sSplit d s = (a, sDrop (sLen d) b, not $ sNull b)+ where (a, b) = sBreak d s++ sSplitAll d s = if sNull b+ then (if c then [a, b] else [a])+ else a : sSplitAll d b+ where (a, b, c) = sSplit d s++ sPadLeft c n s = let len = sLen s+ padLen = max 0 (n - len)+ padStr = sFromString $ replicate padLen c+ in sConcat [padStr, s]+ + sPadRight c n s = let len = sLen s+ padLen = max 0 (n - len)+ padStr = sFromString $ replicate padLen c+ in sConcat [s, padStr] ++ sPadBoth c n s = let len = sLen s+ padLen = (max 0 (n - len))+ padLenR = padLen `quot` 2+ padLenL = padLen - padLenR+ padStrL = sFromString $ replicate padLenL c+ padStrR = sFromString $ replicate padLenR c+ in sConcat [padStrL, s, padStrR]+++instance Strings ByteString where++ sNull = B.null+ sEmpty = B.empty++ sHead = toEnum . fromIntegral . B.head+ sLast = toEnum . fromIntegral . B.last++ sInit = B.init+ sTail = B.tail++ sTake = B.take+ sTakeWhile f = B.takeWhile (f . chr)+ sDrop = B.drop+ sDropWhile f = B.dropWhile (f . chr)++ sBreak = B.breakSubstring++ sStartsWith = flip B.isPrefixOf+ sEndsWith = flip B.isSuffixOf++ sConcat = B.concat+ sLen = B.length++ sTrim s = let (a, b) = B.span (isWhiteSpace . chr) s+ (c, d) = B.spanEnd (isWhiteSpace . chr) b+ in c++ sReverse = B.reverse++ sFromString = B8.pack+ sFromUnicodeString = Enc.encodeUtf8 . T.pack++ sToString = B8.unpack+ sToWord8 = B.unpack+++instance Strings LazyB.ByteString where++ sNull = LazyB.null+ sEmpty = LazyB.empty++ sHead = toEnum . fromIntegral . LazyB.head+ sLast = toEnum . fromIntegral . LazyB.last++ sInit = LazyB.init+ sTail = LazyB.tail++ sTake = LazyB.take . fromIntegral+ sTakeWhile f = LazyB.takeWhile (f . chr)+ sDrop = LazyB.drop . fromIntegral+ sDropWhile f = LazyB.dropWhile (f . chr)++ sStartsWith = flip LazyB.isPrefixOf+ sEndsWith = flip LazyB.isSuffixOf++ sConcat = LazyB.concat+ sLen = fromIntegral . LazyB.length++ sTrim = LazyB.fromChunks . (:[]) . sTrim . B.concat . LazyB.toChunks++ sReverse = LazyB.reverse++ sFromString = LazyB8.pack+ sFromUnicodeString = LazyEnc.encodeUtf8 . LazyT.pack++ sToString = LazyB8.unpack+ sToWord8 = LazyB.unpack+++instance Strings Text where++ sNull = T.null+ sEmpty = T.empty++ sHead = T.head+ sLast = T.last++ sInit = T.init+ sTail = T.tail++ sTake = T.take+ sTakeWhile = T.takeWhile+ sDrop = T.drop+ sDropWhile = T.dropWhile++ sReplace = T.replace+ sBreak = T.breakOn++ sStartsWith = flip T.isPrefixOf+ sEndsWith = flip T.isSuffixOf++ sConcat = T.concat+ sLen = T.length++ sTrim = T.strip++ sPadLeft = flip T.justifyLeft+ sPadRight = flip T.justifyRight+ sPadBoth = flip T.center++ sReverse = T.reverse++ sFromUnicodeString = S.fromString+ sFromString = S.fromString++ sToString = T.unpack+ sToWord8 = B.unpack . Enc.encodeUtf8+++instance Strings LazyT.Text where++ sNull = LazyT.null+ sEmpty = LazyT.empty++ sHead = LazyT.head+ sLast = LazyT.last++ sInit = LazyT.init+ sTail = LazyT.tail++ sTake = LazyT.take . fromIntegral+ sTakeWhile = LazyT.takeWhile+ sDrop = LazyT.drop . fromIntegral+ sDropWhile = LazyT.dropWhile++ sBreak = LazyT.breakOn++ sStartsWith = flip LazyT.isPrefixOf+ sEndsWith = flip LazyT.isSuffixOf++ sConcat = LazyT.concat+ sLen = fromIntegral . LazyT.length++ sTrim = LazyT.strip++ sPadLeft = flip (LazyT.justifyLeft . fromIntegral)+ sPadRight = flip (LazyT.justifyRight . fromIntegral)+ sPadBoth = flip (LazyT.center . fromIntegral)++ sReverse = LazyT.reverse++ sFromUnicodeString = S.fromString+ sFromString = S.fromString++ sToString = LazyT.unpack+ sToWord8 = LazyB.unpack . LazyEnc.encodeUtf8+++instance Strings String where++ sNull = null+ sEmpty = []++ sHead = head+ sLast = last++ sInit = init+ sTail = tail++ sTake = take+ sTakeWhile = takeWhile+ sDrop = drop+ sDropWhile = dropWhile++ sStartsWith = flip L.isPrefixOf+ sEndsWith = flip L.isSuffixOf++ sConcat = concat+ sLen = length++ sTrim = T.unpack . T.strip . T.pack++ sReverse = reverse++ sFromString = id+ sFromUnicodeString = id++ sToString = id+ sToWord8 = B.unpack . Enc.encodeUtf8 . T.pack++-- | Utility class for working with characters.+class Chars a where+ -- | Retrieve the value of the given character.+ ord :: Char -> a++ -- | Construct a character form the given value.+ chr :: a -> Char++instance Chars Int where+ ord = fromIntegral . fromEnum+ chr = toEnum . fromIntegral++instance Chars Word8 where+ ord = fromIntegral . fromEnum+ chr = toEnum . fromIntegral++instance Chars Word16 where+ ord = fromIntegral . fromEnum+ chr = toEnum . fromIntegral++instance Chars Word32 where+ ord = fromIntegral . fromEnum+ chr = toEnum . fromIntegral++instance Chars Word64 where+ ord = fromIntegral . fromEnum+ chr = toEnum . fromIntegral++instance Chars Int8 where+ ord = fromIntegral . fromEnum+ chr = toEnum . fromIntegral++instance Chars Int16 where+ ord = fromIntegral . fromEnum+ chr = toEnum . fromIntegral++instance Chars Int32 where+ ord = fromIntegral . fromEnum+ chr = toEnum . fromIntegral++instance Chars Int64 where+ ord = fromIntegral . fromEnum+ chr = toEnum . fromIntegral++instance Chars Integer where+ ord = fromIntegral . fromEnum+ chr = toEnum . fromIntegral++
+ strings.cabal view
@@ -0,0 +1,18 @@+Name: strings+Version: 1.0.0+Synopsis: Functions for working with strings, including Text, ByteString, etc.+Description: Functions for working with strings, including Text, ByteString, etc.+License: MIT+License-File: LICENSE+Author: Julian Fleischer+Maintainer: julian.fleischer@fu-berlin.de+Build-Type: Simple+Cabal-Version: >= 1.4+Category: Text, String, Utility+Stability: provisional++Library+ Exposed-Modules: Data.Strings+ Build-Depends: base >= 4 && < 5, bytestring >= 0.9 && < 0.10, text >= 0.10+ Hs-Source-Dirs: src+