reading blog

URI Escaping in Haskell (or, reinventing the wheel in style)

February 13, 2007

As part of my efforts to learn more about functional programming in general and Haskell in specific, I chose a small project that was tangentially related to the work I do in my web programming work at Enterity.  If anyone out there knows of a built-in for converting from Int to Hex and back again, I'd be much obliged.  I didn't see anything skimming the standard libraries via Zvon.org


module Main where

import System.Environment
import Char
import List

main :: IO ()
main = do args <- getArgs
          case ( args !! 0 ) of
              "encode" -> putStrLn ( encode $ concat $ tail args )
              "decode" -> putStrLn ( decode $ head   $ tail args )

-- --------------------------------------

encode :: String -> String
encode str = concat $ map encodeChar str

decode :: String -> String
decode ""     = ""
decode (c:cs) = case c of
        '%'       -> fromHex( take 2 cs ) : decode( drop 2 cs )
        otherwise -> c                    : decode cs

-- --------------------------------------

encodeChar :: Char -> String
encodeChar c =
    case isLegalChar c of
      True      -> c   : ""
      otherwise -> '%' : ( toHex . ord ) c

isLegalChar :: Char -> Bool
isLegalChar c = any (c==) ( [ 'A' .. 'Z' ] ++ ['a' .. 'z'] ++ [ '0'..'9' ] ++ "-_.!~*'()" )

-- --------------------------------------

toHex :: Int -> String
toHex 0 = ""
toHex x =
    let rem = x `mod` 16
        in toHex( ( x-rem ) `div` 16 ) ++ [ toChar rem  ]

fromHex :: String -> Char
fromHex hx =
    let a = fromChar $ head hx
        z = fromChar $ head $ tail hx
        in chr( a * 16  + z )
        
-- --------------------------------------

toChar :: Int -> Char
toChar x = ( [ '0' .. '9' ] ++ [ 'a' .. 'f' ] ) !! x

fromChar :: Char -> Int
fromChar x = case findIndex (x==) ( [ '0' .. '9' ] ++ [ 'a' .. 'f' ] ) of
                 Nothing -> 0
                 Just y  -> y