(define encode-replacements (list (list " " "%20") (list " " "+") (list "!" "%21") (list "#" "%23") (list "$" "%24") (list "%" "%25") (list "&" "%26") (list "'" "%27") (list "(" "%28") (list ")" "%29") (list "*" "%2A") (list "+" "%2B") (list "," "%2C") (list "/" "%2F") (list ":" "%3A") (list ";" "%3B") (list "=" "%3D") (list "?" "%3F") (list "@" "%40") (list "[" "%5B") (list "]" "%5D") (list "<" "%3C") (list ">" "%3E") (list "\\" "%5C") (list "\"" "%22") (list "\n" "%0A") (list "\r" "%0D"))) (define decode-replacements (map reverse encode-replacements)) (define (get-replacement key mode) (let ((r (if (string=? mode "encode") (assoc key encode-replacements) (assoc key decode-replacements)))) (if r (car (cdr r)) key))) (define (endecode mode s) (if (not s) "" (letrec ((s-length (string-length s)) (looper (lambda (i result) (if (< i s-length) (let ((key-length (if (and (string=? mode "decode") (string=? (string-copy s i (+ i 1)) "%") (> s-length (+ i 2))) 3 1))) (looper (+ i key-length) (string-append result (get-replacement (string-copy s i (+ i key-length)) mode)))) result)))) (looper 0 "")))) (define (url-encode str) (cond ((string? str) (endecode "encode" str)) (else str))) (define (url-decode str) (cond ((string? str) (endecode "decode" str)) (else str)))