1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
|
{-# LANGUAGE FlexibleContexts #-}
--------------------------------------------------------------------------------
-- | Miscellaneous string manipulation functions.
module Hakyll.Core.Util.String
( trim
, replaceAll
, splitAll
, needlePrefix
, removeWinPathSeparator
) where
--------------------------------------------------------------------------------
import Data.Char (isSpace)
import Data.List (isPrefixOf)
import Data.Maybe (listToMaybe)
import Text.Regex.TDFA ((=~~))
--------------------------------------------------------------------------------
-- | Trim a string (drop spaces, tabs and newlines at both sides).
trim :: String -> String
trim = reverse . trim' . reverse . trim'
where
trim' = dropWhile isSpace
--------------------------------------------------------------------------------
-- | A simple (but inefficient) regex replace funcion
replaceAll :: String -- ^ Pattern
-> (String -> String) -- ^ Replacement (called on match)
-> String -- ^ Source string
-> String -- ^ Result
replaceAll pattern f source = replaceAll' source
where
replaceAll' src = case listToMaybe (src =~~ pattern) of
Nothing -> src
Just (o, l) ->
let (before, tmp) = splitAt o src
(capture, after) = splitAt l tmp
in before ++ f capture ++ replaceAll' after
--------------------------------------------------------------------------------
-- | A simple regex split function. The resulting list will contain no empty
-- strings.
splitAll :: String -- ^ Pattern
-> String -- ^ String to split
-> [String] -- ^ Result
splitAll pattern = filter (not . null) . splitAll'
where
splitAll' src = case listToMaybe (src =~~ pattern) of
Nothing -> [src]
Just (o, l) ->
let (before, tmp) = splitAt o src
in before : splitAll' (drop l tmp)
--------------------------------------------------------------------------------
-- | Find the first instance of needle (must be non-empty) in haystack. We
-- return the prefix of haystack before needle is matched.
--
-- Examples:
--
-- > needlePrefix "cd" "abcde" = "ab"
--
-- > needlePrefix "ab" "abc" = ""
--
-- > needlePrefix "ab" "xxab" = "xx"
--
-- > needlePrefix "a" "xx" = "xx"
needlePrefix :: String -> String -> Maybe String
needlePrefix needle haystack = go [] haystack
where
go _ [] = Nothing
go acc xss@(x:xs)
| needle `isPrefixOf` xss = Just $ reverse acc
| otherwise = go (x : acc) xs
--------------------------------------------------------------------------------
-- | Translate native Windows path separators '\\' to '/' if present.
removeWinPathSeparator :: String -> String
removeWinPathSeparator = concatMap (\c -> if c == '\\' then ['/'] else [c])
|