Question

My goal is to take an alist (the alist is the one passed to Drakma's "parameters" param; but this doesn't really matter for this question) and to serialize it into some form of string (in this case, a HTTP parameters string).

So let's take that list:

    (list (cons 1 2) (cons 3 4) (cons 5 6))

Then what I want, is to endup with a string formatted like this:

    "?1=2&3=4&5=6"

What I did come up with so far is:

    (defvar *s* 
      (make-array 0 
              :element-type 'character 
              :adjustable t 
              :fill-pointer 0))

    ;; (serialize-params) will return a properly formatted string 
    ;; that will be used elsewhere in another function
    (defun serialize-params (params)
      (loop for (a . b) in params
         do (format *s* "~a=~a&" a b))
      (concatenate 'string "?" (trim *s*)))

    ;; Utility function to remove the last character of a string
    (defun trim (str)
      (subseq str 0 (- (length str) 1)))

It kind of work, but I really don't like this for a few reasons:

  • I don't want to use a special variable
  • everytime I run (serialize-params (...)), *s* just append to the previous call

I think that to solve my issue, I have to use loop in some special way and probably that I would have to bind a lexical variable within my function. The problem is that I am not sure how I could append each iteration of (format nil "...") to that lexical variable...

Disclaimer: I am really new at lisp.

Was it helpful?

Solution

with-output-to-string seems to be a good fit for your problem. It makes a stream you can write to in a loop, and returns whatever you wrote as a string:

(with-output-to-string (s)
   (loop with first = t
         for (a . b) in params
         if first 
           do (setq first nil)
              (princ "?" s)
         else
           do (princ "&" s)
         end
         do (format s "~a=~a" a b)))
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top