Hatena::Groupcadr

わだばLisperになる このページをアンテナに追加 RSSフィード

2004 | 12 |
2005 | 01 | 02 | 07 | 10 | 11 |
2006 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 11 |

2010-04-03

KMRCLを眺める(130) ENCODE-URI-STRING

| 13:45 | KMRCLを眺める(130) ENCODE-URI-STRING - わだばLisperになる を含むブックマーク はてなブックマーク - KMRCLを眺める(130) ENCODE-URI-STRING - わだばLisperになる

今回はKMRCLのstrings.lispから、ENCODE-URI-STRINGです。

動作は、

(KL:ENCODE-URI-STRING "/usr/bin/ls")
⇒ "%2Fusr%2Fbin%2Fls"

というところ

定義は

(defun encode-uri-string (query)
  "Escape non-alphanumeric characters for URI fields"
  (declare (simple-string query)
           (optimize (speed 3) (safety 0) (space 0)))
  (do* ((count (count-string-char-if #'non-alphanumericp query))
        (len (length query))
        (new-len (+ len (* 2 count)))
        (str (make-string new-len))
        (spos 0 (1+ spos))
        (dpos 0 (1+ dpos)))
      ((= spos len) str)
    (declare (fixnum count len new-len spos dpos)
             (simple-string str))
    (let ((ch (schar query spos)))
      (if (non-alphanumericp ch)
          (let ((c (char-code ch)))
            (setf (schar str dpos) #\%)
            (incf dpos)
            (setf (schar str dpos) (hexchar (logand (ash c -4) 15)))
            (incf dpos)
            (setf (schar str dpos) (hexchar (logand c 15))))
        (setf (schar str dpos) ch)))))0

となっています。

  • non-alphanumericpでエンコードする必要のある文字を判定
  • エンコードして長くなる分の文字数を足した長さの文字列を新しく作成
  • 元の文字列を読みながら、新しい文字列にエンコードしつつコピー

という感じのようです。

(hexchar (logand (ash c -4) 15)と(hexchar (logand c 15))のところが気になりますが、一文字ずつ処理する必要があるため、20のような16進数を2と0の文字に分けている様子

ちなみに、以前眺めたnon-alphanumericpで判定しているのと、ASCII以外は考慮していないようなので、

;; UTF-8
(KL:ENCODE-URI-STRING "逆引き Scheme")
⇒ "逆引き%20Scheme"

ということになってしまいます。