packages feed

antelude-0.1.0: src/Antelude/String.hs

{- |
Module      : Antelude.String
Description : Contains some functions for Strings.
Maintainer  : dneavesdev@pm.me
-}
module Antelude.String
    ( String
    , String.IsString (..)
      -- | Reexport from 'Data.String'
    , String.lines
      -- | Reexport from 'Data.String'
    , String.unlines
      -- | Reexport from 'Data.String'
    , String.unwords
      -- | Reexport from 'Data.String'
    , String.words
    , bytestring
    , bytestringLazy
    , contains
    , join
    , joinWith
    , pad
    , padLeft
    , padRight
    , replace
    , split
    , text
    , textLazy
    , trim
    , trimLeft
    , trimRight
    , unBytestring
    , unBytestringLazy
    , unText
    , unTextLazy
    ) where

import safe           Antelude.Function              ( (|>) )
import safe           Antelude.Internal.TypesClasses
    ( Bool (..)
    , ByteString
    , ByteStringLazy
    , Char
    , Int
    , List
    , String
    , Text
    , TextLazy
    , (<>)
    , (==)
    )
import safe qualified Antelude.List                  as List
import safe           Antelude.Tuple.Pair            ( first )

import safe qualified Data.ByteString.Char8          as BC
import safe qualified Data.ByteString.Lazy.Char8     as BLC
import safe qualified Data.String                    as String
import safe qualified Data.Text                      as TS
import safe qualified Data.Text.Lazy                 as TL


-- | Given a substring, separate a 'String' into a 'List' containing all parts between (and not including) the substring.
split :: String -> String -> List String
split splitWith splitThis =
    let splitterLength :: Int
        splitterLength = List.length splitWith

        splitFunc :: (List String, String) -> String -> (List String, String)
        splitFunc (accum, []) [] = (accum, [])
        splitFunc (accum, []) tmp = (List.append tmp accum, [])
        splitFunc (accum, str) tmp =
            if List.isPrefixOf splitWith str
            then
                splitFunc
                ( case tmp of
                    "" -> accum
                    _  -> List.append tmp accum
                , List.drop splitterLength str
                )
                []
            else splitFunc (accum, List.drop 1 str) (tmp <> List.take 1 str)
    in  splitFunc ([], splitThis) [] |> first


-- | Given a "replaceable" substring to replace, and a "replacement" substring, replace all instances of the "replaceable" within a 'String' with the "replacement".
replace :: String -> String -> String -> String
replace _ _ [] = []
replace [] _ string = string
replace replaceThis replaceWith string =
    let replacerLength :: Int
        replacerLength = List.length replaceThis

        replaceFunc :: (List String, String) -> String -> (List String, String)
        replaceFunc (accum, []) [] = (accum, [])
        replaceFunc (accum, []) tmp = (List.append tmp accum, [])
        replaceFunc (accum, str) tmp =
            if List.isPrefixOf replaceThis str
            then
                replaceFunc
                ( List.append (tmp <> replaceWith) accum
                , List.drop replacerLength str
                )
                []
            else replaceFunc (accum, List.drop 1 str) (tmp <> List.take 1 str)
    in  replaceFunc ([], string) [] |> first |> join


-- | Given a substring, see if it is within a provided 'String'.
contains :: String -> String -> Bool
contains _ [] = False
contains [] _ = True
contains substring string =
    List.isInfixOf substring string


-- | Join a 'List' of 'String's together with no additional characters
join :: List String -> String
join = List.intercalate ""


-- | Join a 'List' of 'String's together with a specified character
joinWith :: String -> List String -> String
joinWith = List.intercalate


-- | Add a specified number of 'Char's to the left side
padLeft :: Int -> Char -> String -> String
padLeft qnt chr str =
    (List.repeat chr |> List.take qnt) <> str


-- | Add a specified number of 'Char's to the right side
padRight :: Int -> Char -> String -> String
padRight qnt chr str =
    str <> (List.repeat chr |> List.take qnt)


-- | Add a specified number of 'Char's to the both side
pad :: Int -> Char -> String -> String
pad qnt chr str =
    (List.repeat chr |> List.take qnt) <> str <> (List.repeat chr |> List.take qnt)


-- | Remove 'Char's from the left
trimLeft :: Char -> String -> String
trimLeft chr str =
    str
        |> List.dropWhile (== chr)


-- | Remove 'Char's from the right
trimRight :: Char -> String -> String
trimRight chr str =
    str
        |> List.reverse
        |> List.dropWhile (== chr)
        |> List.reverse


-- | Remove 'Char's from both sides
trim :: Char -> String -> String
trim chr str =
    str
        |> trimRight chr
        |> trimLeft chr


-- | Turn a String into a strict Text
text :: String -> Text
text = TS.pack


-- | Turn a strict Text into a String
unText :: Text -> String
unText = TS.unpack


-- | Turn a String into a lazy Text
textLazy :: String -> TextLazy
textLazy = TL.pack


-- | Turn a lazy Text into a String
unTextLazy :: TextLazy -> String
unTextLazy = TL.unpack


-- | Turn a String into a strict ByteString
bytestring :: String -> ByteString
bytestring = BC.pack


-- | Turn a strict ByteString into a String
unBytestring :: ByteString -> String
unBytestring = BC.unpack


-- | Turn a String into a lazy ByteString
bytestringLazy :: String -> ByteStringLazy
bytestringLazy = BLC.pack


-- | Turn a lazy ByteString into a String
unBytestringLazy :: ByteStringLazy -> String
unBytestringLazy = BLC.unpack