MatthewRock
MatthewRock

Reputation: 1091

Format over list: use arguments that aren't in list

Here's a code snippet that I wrote, but doesn't work:

(let ((separator "|")
      (text '("Just" "do" "it" "!")))
  (format t "~{~A~A~%~}" text separator))

The output should look like:

Just|
do|
it|
!|

However, it won't work like that - when I'm inside ~{~}, I don't know how I can add elements from outside the list. I could do this:

(format t "~{~A|~%~}" text)

but this does not allow me to use separator from variable, and that's what I'm after.

Now I know that I could merge text with separator, by adding separator in every even place, but that looks ugly to me. Is there other way to do it in format?

Upvotes: 3

Views: 162

Answers (3)

Rainer Joswig
Rainer Joswig

Reputation: 139251

Changing the answer from renzo a bit: if we use SPECIAL declarations, we don't need the global variable:

(defun %d1 (stream arg &rest args)
  (declare (ignore args)
           (special delim))
  (princ arg stream)
  (princ delim stream))

(defun my-print (list delim)
  (declare (special delim))
  (format nil "~{~/%d1/~%~}" list))

Upvotes: 1

Renzo
Renzo

Reputation: 27414

You could use a Tilde Slash format directive, that allows a user-defined function as format specifier. This is just to give you a possible example, many variations on this are possible:

CL-USER> (defvar *separator* " ")
*SEPARATOR*
CL-USER> (defun q(stream arg &rest args)
           (declare (ignore args))
           (format stream "~a~a" arg *separator*))
Q
CL-USER> (let ((*separator* "|")
               (text '("Just" "do" "it" "!")))
           (format t "~{~/q/~%~}" text))
Just|
do|
it|
!|
NIL
CL-USER> (let ((*separator* "+++")
               (text '("Just" "do" "it" "!")))
           (format t "~{~/q/~%~}" text))
Just+++
do+++
it+++
!+++
NIL
CL-USER> 

Upvotes: 2

Rainer Joswig
Rainer Joswig

Reputation: 139251

This is a hack:

CL-USER 49 > (let ((separator "|")
                   (text '("Just" "do" "it" "!")))
                (format t
                        (concatenate 'string "~{~A" separator "~%~}")
                        text))
Just|
do|
it|
!|

Escaping tilde in the separator string:

CL-USER 56 > (flet ((fix-tilde (string)
                      (with-output-to-string (s)
                        (loop for c across string
                              when (char= c #\~)
                              do (write-string "~~" s)
                              else do (write-char c s)))))
               (let ((separator (fix-tilde "~a~a"))
                     (text '("Just" "do" "it" "!")))
                 (format t
                         (concatenate 'string "~{~A" separator "~%~}")
                         text)))
Just~a~a
do~a~a
it~a~a
!~a~a

Upvotes: 4

Related Questions