module Text.XML.HXT.DOM.Util
( stringTrim
, stringToLower
, stringToUpper
, stringAll
, stringFirst
, stringLast
, normalizeNumber
, normalizeWhitespace
, normalizeBlanks
, escapeURI
, textEscapeXml
, stringEscapeXml
, attrEscapeXml
, stringToInt
, stringToHexString
, charToHexString
, intToHexString
, hexStringToInt
, decimalStringToInt
, doubles
, singles
, noDoubles
, swap
, partitionEither
, toMaybe
, uncurry3
, uncurry4
)
where
import Data.Char
import Data.List
import Data.Maybe
stringTrim :: String -> String
stringTrim = reverse . dropWhile isSpace . reverse . dropWhile isSpace
stringToUpper :: String -> String
stringToUpper = map toUpper
stringToLower :: String -> String
stringToLower = map toLower
stringAll :: (Eq a) => [a] -> [a] -> [Int]
stringAll x = map fst . filter ((x `isPrefixOf`) . snd) . zip [0..] . tails
stringFirst :: (Eq a) => [a] -> [a] -> Maybe Int
stringFirst x = listToMaybe . stringAll x
stringLast :: (Eq a) => [a] -> [a] -> Maybe Int
stringLast x = listToMaybe . reverse . stringAll x
normalizeNumber :: String -> String
normalizeNumber
= reverse . dropWhile (== ' ') . reverse .
dropWhile (\x -> x == '0' || x == ' ')
normalizeWhitespace :: String -> String
normalizeWhitespace = unwords . words
normalizeBlanks :: String -> String
normalizeBlanks = map (\ x -> if isSpace x then ' ' else x)
escapeURI :: String -> String
escapeURI ref
= concatMap replace ref
where
notAllowed :: Char -> Bool
notAllowed c
= c < '\31'
||
c `elem` ['\DEL', ' ', '<', '>', '\"', '{', '}', '|', '\\', '^', '`' ]
replace :: Char -> String
replace c
| notAllowed c
= '%' : charToHexString c
| otherwise
= [c]
escapeXml :: String -> String -> String
escapeXml escSet
= concatMap esc
where
esc c
| c `elem` escSet
= "&#" ++ show (fromEnum c) ++ ";"
| otherwise
= [c]
stringEscapeXml :: String -> String
stringEscapeXml = escapeXml "<>\"\'&"
textEscapeXml :: String -> String
textEscapeXml = escapeXml "<&"
attrEscapeXml :: String -> String
attrEscapeXml = escapeXml "<>\"\'&\n\r\t"
stringToInt :: Int -> String -> Int
stringToInt base digits
= sign * (foldl acc 0 $ concatMap digToInt digits1)
where
splitSign ('-' : ds) = ((-1), ds)
splitSign ('+' : ds) = ( 1 , ds)
splitSign ds = ( 1 , ds)
(sign, digits1) = splitSign digits
digToInt c
| c >= '0' && c <= '9'
= [ord c - ord '0']
| c >= 'A' && c <= 'Z'
= [ord c - ord 'A' + 10]
| c >= 'a' && c <= 'z'
= [ord c - ord 'a' + 10]
| otherwise
= []
acc i1 i0
= i1 * base + i0
hexStringToInt :: String -> Int
hexStringToInt = stringToInt 16
decimalStringToInt :: String -> Int
decimalStringToInt = stringToInt 10
stringToHexString :: String -> String
stringToHexString = concatMap charToHexString
charToHexString :: Char -> String
charToHexString c
= [ fourBitsToChar (c' `div` 16)
, fourBitsToChar (c' `mod` 16)
]
where
c' = fromEnum c
intToHexString :: Int -> String
intToHexString i
| i == 0
= "0"
| i > 0
= intToStr i
| otherwise
= error ("intToHexString: negative argument " ++ show i)
where
intToStr 0 = ""
intToStr i' = intToStr (i' `div` 16) ++ [fourBitsToChar (i' `mod` 16)]
fourBitsToChar :: Int -> Char
fourBitsToChar i = "0123456789ABCDEF" !! i
doubles :: Eq a => [a] -> [a]
doubles
= doubles' []
where
doubles' acc []
= acc
doubles' acc (e : s)
| e `elem` s
&&
e `notElem` acc
= doubles' (e:acc) s
| otherwise
= doubles' acc s
singles :: Eq a => [a] -> [a]
singles
= singles' []
where
singles' acc []
= acc
singles' acc (e : s)
| e `elem` s
||
e `elem` acc
= singles' acc s
| otherwise
= singles' (e : acc) s
noDoubles :: Eq a => [a] -> [a]
noDoubles []
= []
noDoubles (e : s)
| e `elem` s = noDoubles s
| otherwise = e : noDoubles s
swap :: (a,b) -> (b,a)
swap (x,y) = (y,x)
partitionEither :: [Either a b] -> ([a], [b])
partitionEither =
foldr (\x ~(ls,rs) -> either (\l -> (l:ls,rs)) (\r -> (ls,r:rs)) x) ([],[])
toMaybe :: Bool -> a -> Maybe a
toMaybe False _ = Nothing
toMaybe True x = Just x
uncurry3 :: (a -> b -> c -> d) -> (a, b, c) -> d
uncurry3 f ~(a, b, c) = f a b c
uncurry4 :: (a -> b -> c -> d -> e) -> (a, b, c, d) -> e
uncurry4 f ~(a, b, c, d) = f a b c d