URLエスケープ

30分プログラム、その194。SchemeでURLエスケープを実装してみる。

URLエスケープは以下のルールで行なわれる。

  • ピリオド("." アスキーコードは0x2E)、 マイナス("-" アスキーコードは0x2D)と アンダーバー("_" アスキーコードは0x5F)はそのまま
  • アスキー文字のアルファベット("A"から"Z"の大文字と"a"から"z"の小文字)と、 数字("0"から"9"まで)もそのまま
  • 空白(" " アスキーコードは0x20)はプラス("+" アスキーコードは0x2B)に
  • 以上の3つの規則に当てはまらない文字は、 全て、 "%16進数表記"に変換する

http://www.kinet.or.jp/hiromin/cgi_introduction/appendix/url_encode.html

使い方

gosh> (encode "http://google.com/")
"http%3A%2F%2Fgoogle.com%2F"

gosh> (decode (encode "http://google.com/"))
"http://google.com/"

ソースコード

#! /opt/local/bin/gosh
;; -*- mode:scheme; coding:utf-8 -*-
;;
;; url.scm - url escape
;;
;; Copyright(C) 2007 by mzp
;; Author: MIZUNO Hiroki / mzpppp at gmail dot com
;; http://howdyworld.org
;;
;; Timestamp: 2007/11/30 23:30:58
;;
;; This program is free software; you can redistribute it and/or
;; modify it under the same terms as Scheme itself.
;;
(use srfi-1)
(use srfi-14)
(use text.tree)

(define (is-alnum c)
  (char-set-contains? (char-set-union char-set:lower-case char-set:upper-case) c))

(define (encode-char c)
  (case c
    ((#\. #\- #\_) c)
    ((\#Space) #\+)
    (else (if (is-alnum c)
	      c
	      (format "%~X" (char->integer c))))))

(define (encode url)
  (tree->string (map encode-char (string->list url))))

(define (decode url)
  (regexp-replace-all #/%([0-9A-Fa-f]{2})/
		      url
		      (lambda (m) 
			(let1 num (rxmatch-substring m 1)
			  (integer->char (string->number num 16))))))