From: ramza2
Subject: With format, how to print a variable number of spaces
Date: 
Message-ID: <1149480580.254815.87860@j55g2000cwa.googlegroups.com>
How can I print a variable number of spaces.  In python I might do:

print " " * 3

How would I use 'format' to do something similar.

From: Rob Warnock
Subject: Re: With format, how to print a variable number of spaces
Date: 
Message-ID: <IuidnXozJ52sfR7ZnZ2dnUVZ_t-dnZ2d@speakeasy.net>
ramza2 <············@gmail.com> wrote:
+---------------
| How can I print a variable number of spaces.  In python I might do:
|   print " " * 3
| How would I use 'format' to do something similar.
+---------------

There are several ways. It depends on what you're really trying to do.
If you want to tabulate to a specific column position then "~T" with
a variable parameter ("~VT") will do that:

    > (loop for i below 20
	    for col = (+ 32 (round (* 8 (sin (* i pi 1/4))))) do
	(format t "~&Let's tab from here to~vtHERE.~%" col))
    Let's tab from here to          HERE.
    Let's tab from here to                HERE.
    Let's tab from here to                  HERE.
    Let's tab from here to                HERE.
    Let's tab from here to          HERE.
    Let's tab from here to    HERE.
    Let's tab from here to  HERE.
    Let's tab from here to    HERE.
    Let's tab from here to          HERE.
    Let's tab from here to                HERE.
    Let's tab from here to                  HERE.
    Let's tab from here to                HERE.
    Let's tab from here to          HERE.
    Let's tab from here to    HERE.
    Let's tab from here to  HERE.
    Let's tab from here to    HERE.
    Let's tab from here to          HERE.
    Let's tab from here to                HERE.
    Let's tab from here to                  HERE.
    Let's tab from here to                HERE.
    NIL
    > 

If you're trying to do variable widths with things other than spaces,
you can use the "mincol" & "padchar" options of "~A":

    > (loop for i below 20
	    for col = (+ 20 (round (* 8 (sin (* i pi 1/4))))) do
	(format t "~&Let's draw from here to ~V,,,··@A~%" col "> here"))

    Let's draw from here to --------------> here
    Let's draw from here to --------------------> here
    Let's draw from here to ----------------------> here
    Let's draw from here to --------------------> here
    Let's draw from here to --------------> here
    Let's draw from here to --------> here
    Let's draw from here to ------> here
    Let's draw from here to --------> here
    Let's draw from here to --------------> here
    Let's draw from here to --------------------> here
    Let's draw from here to ----------------------> here
    Let's draw from here to --------------------> here
    Let's draw from here to --------------> here
    Let's draw from here to --------> here
    Let's draw from here to ------> here
    Let's draw from here to --------> here
    Let's draw from here to --------------> here
    Let's draw from here to --------------------> here
    Let's draw from here to ----------------------> here
    Let's draw from here to --------------------> here
    NIL
    > 

For more complicated stuff, SUBSEQ can be useful:

    > (defparameter *digits* (apply 'concatenate 'string
			            (loop for i below 10
				      collect "0123456789")))
    > (loop for i below 20
	    for col = (+ 20 (round (* 8 (sin (* i pi 1/4))))) do
	(format t "~&~A = ~32T~D chars~%" (subseq *digits* 0 col) col))

    01234567890123456789 =          20 chars
    01234567890123456789012345 =    26 chars
    0123456789012345678901234567 =  28 chars
    01234567890123456789012345 =    26 chars
    01234567890123456789 =          20 chars
    01234567890123 =                14 chars
    012345678901 =                  12 chars
    01234567890123 =                14 chars
    01234567890123456789 =          20 chars
    01234567890123456789012345 =    26 chars
    0123456789012345678901234567 =  28 chars
    01234567890123456789012345 =    26 chars
    01234567890123456789 =          20 chars
    01234567890123 =                14 chars
    012345678901 =                  12 chars
    01234567890123 =                14 chars
    01234567890123456789 =          20 chars
    01234567890123456789012345 =    26 chars
    0123456789012345678901234567 =  28 chars
    01234567890123456789012345 =    26 chars
    NIL
    > 


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Joe Marshall
Subject: Re: With format, how to print a variable number of spaces
Date: 
Message-ID: <1149529703.444989.223420@i40g2000cwc.googlegroups.com>
Rob Warnock wrote:
>
>     > (loop for i below 20
> 	    for col = (+ 20 (round (* 8 (sin (* i pi 1/4))))) do
> 	(format t "~&Let's draw from here to ~V,,,··@A~%" col "> here"))
>
>     Let's draw from here to --------------> here
>     Let's draw from here to --------------------> here
>     Let's draw from here to ----------------------> here
>     Let's draw from here to --------------------> here
>     Let's draw from here to --------------> here
>     Let's draw from here to --------> here
>     Let's draw from here to ------> here
>     Let's draw from here to --------> here
>     Let's draw from here to --------------> here
>     Let's draw from here to --------------------> here
>     Let's draw from here to ----------------------> here
>     Let's draw from here to --------------------> here
>     Let's draw from here to --------------> here
>     Let's draw from here to --------> here
>     Let's draw from here to ------> here
>     Let's draw from here to --------> here
>     Let's draw from here to --------------> here
>     Let's draw from here to --------------------> here
>     Let's draw from here to ----------------------> here
>     Let's draw from here to --------------------> here
>     NIL
>     > 

Show-off!
From: Szymon
Subject: Re: With format, how to print a variable number of spaces
Date: 
Message-ID: <e612vb$o3r$1@nemesis.news.tpi.pl>
Hi.

Nice example :-) may I put it on my blog ?

> For more complicated stuff, SUBSEQ can be useful:
> 
>     > (defparameter *digits* (apply 'concatenate 'string
> 			            (loop for i below 10
> 				      collect "0123456789")))

apply+concatenate is IMO not best idea here..

(defparameter *digits*
  (with-output-to-string (*standard-output*)
    (loop repeat 10 do (princ "0123456789"))))


>     > (loop for i below 20
> 	    for col = (+ 20 (round (* 8 (sin (* i pi 1/4))))) do
> 	(format t "~&~A = ~32T~D chars~%" (subseq *digits* 0 col) col))

If *digits* is a list of characters it is possible to avoid copying
(of course one can use displaced string..)

(defparameter *digits* ; it's circular list of characters
  (let ((list (coerce "0123456789" 'list)))
    (prog1 list (rplacd (last list) list))))

(loop for i below 20
      for col = (+ 20 (round (* 8 (sin (* i pi 1/4))))) do
      (format t "~&~V{~C~} = ~32T~D chars~%" col *digits* col))

.
From: Steven M. Haflich
Subject: Re: With format, how to print a variable number of spaces
Date: 
Message-ID: <7IPgg.46148$Lm5.38300@newssvr12.news.prodigy.com>
ramza2 wrote:
> How can I print a variable number of spaces.  In python I might do:
> 
> print " " * 3
> 
> How would I use 'format' to do something similar.

You want the ~T format control.

See here: http://www.franz.com/support/documentation/8.0/ansicl/subsubse/tildetta.htm
From: Szymon
Subject: Re: With format, how to print a variable number of spaces
Date: 
Message-ID: <e61ghm$fei$1@atlantis.news.tpi.pl>
ramza2 wrote:
> How can I print a variable number of spaces.  In python I might do:
> 
> print " " * 3
> 
> How would I use 'format' to do something similar.

(format t "~V{~C~}" 3 '#0=(#\Space . #0#))

(-;
From: Frank Buss
Subject: Re: With format, how to print a variable number of spaces
Date: 
Message-ID: <16px90qk60wta$.1ufg94b87p5zh.dlg@40tude.net>
ramza2 wrote:

> How can I print a variable number of spaces.  In python I might do:
> 
> print " " * 3
> 
> How would I use 'format' to do something similar.

You could write (format t (* " " 3)), if you write this before:

(shadow '*)

(defun * (&rest arguments)
  (loop for factor in arguments
        with result = 1
        finally (return result) do
        (if (and (typep result 'number) (typep factor 'number))
            (setf result (cl:* result factor))
          (progn
            (when (typep result 'number) (rotatef result factor))
            (loop for i from 1 below factor
                  with append = result do
                  (setf result (concatenate 'string result append)))))))

This works the same like the Python "*" (I hope) :

Lisp:

CL-USER > (* 2 "hello " 3)
"hello hello hello hello hello hello "

Python:

>>> 2 * "hello " * 3
'hello hello hello hello hello hello '

-- 
Frank Buss, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
From: Marcin 'Qrczak' Kowalczyk
Subject: Re: With format, how to print a variable number of spaces
Date: 
Message-ID: <87u06zv55e.fsf@qrnik.zagroda>
Frank Buss <··@frank-buss.de> writes:

>             (loop for i from 1 below factor
>                   with append = result do
>                   (setf result (concatenate 'string result append)))))))

This has quadratic time cost. Could be done in linear time.

-- 
   __("<         Marcin Kowalczyk
   \__/       ······@knm.org.pl
    ^^     http://qrnik.knm.org.pl/~qrczak/
From: Szymon
Subject: Re: With format, how to print a variable number of spaces
Date: 
Message-ID: <e626ku$465$1@nemesis.news.tpi.pl>
Marcin 'Qrczak' Kowalczyk wrote:
> Frank Buss <··@frank-buss.de> writes:
> 
>>             (loop for i from 1 below factor
>>                   with append = result do
>>                   (setf result (concatenate 'string result append)))))))
> 
> This has quadratic time cost. Could be done in linear time.

indeed..

(defun x (&rest args)
  (let ((num 1)
        (stream (make-string-output-stream)))
    (dolist (thing args)
      (etypecase thing
        ((integer 0) (setq num (* thing num)))
        (string (write-string thing stream))))
    (let* ((string (get-output-stream-string stream))
           (result-length (* (length string) num))
           (result (make-string result-length)))
      (loop for index by (length string) below result-length
            do (replace result string :start1 index))
      result)))

CL-USER> (x 3 "x")
"xxx"

CL-USER> (x "y" 3 "x")
"yxyxyx"

CL-USER> (x 2 "foo" 2 " ")
"foo foo foo foo "
From: Kent M Pitman
Subject: Re: With format, how to print a variable number of spaces
Date: 
Message-ID: <u8xobwdyn.fsf@nhplace.com>
"ramza2" <············@gmail.com> writes:

> How can I print a variable number of spaces.  In python I might do:
> 
> print " " * 3
> 
> How would I use 'format' to do something similar.

It's quite annoying that there's not something specific for this.

The idiom I always use is based on ~{...~} because it iterates over 
something.  e.g.,

  (format nil "~{~A~}" '(A B C D E F)) => "ABCDEF"

You can limit it to only n iterations with a parameter:

  (format nil "~2{~A~}" '(A B C D E F)) => "AB"

And you can make the parameter variable with

  (format nil "~V{~A~}" 2 '(A B C D E F)) => "AB"

The problem is that if you run out early, it will stop. e.g.,

  (format nil "~8{~A~}" '(A B C D E F)) => "ABCDEF"

so if you think you can get away with:

  (format nil "~8{x~}" '()) => ""

you'll find you end up with no spaces rather than 8 because the list
to iterate across has been emptied.  However, if you supply a non-empty
list, this will be bypassed and then you can use the parameter:

  (format nil "~8{x~}" '(NEVER-USED)) => "xxxxxxxx"

So if you do:

  (defun spaces (n) (format nil "~V{ ~}" n '(IGNORED)))

you'll get what you want if you want to use FORMAT.

...  not that I'd advocate FORMAT.  I'd use:

  (make-string 5 :initial-element #\Space)

The only reason to know about the ~{...~} idiom above is if you're already
doing a FORMAT string with other things in it and you don't want to drop
out of the FORMAT paradigm in order to get some spaces.

(Although Szymon <···········@o2.pl>'s solution of using a circular list is
something I do, too, sometimes with the dotted notation and sometimes with
a circular-list function that I have in my toolbox.  It's particularly useful
here if you want to make explicit that it's a Space or a Tab or something,
which isn't always apparent if it's just whitespace in a file...  Also, that
circular list technique is useful for a lot of other fun things that repeat,
and is well worth knowing for other purposes.  It may occasionally trip up
compiler or fasl-dumper bugs if circularity isn't handled right, but such
things should be reported so they get fixed.)
From: Pascal Bourguignon
Subject: Re: With format, how to print a variable number of spaces
Date: 
Message-ID: <873bej5dcn.fsf@thalassa.informatimago.com>
Kent M Pitman <······@nhplace.com> writes:

> "ramza2" <············@gmail.com> writes:
>
>> How can I print a variable number of spaces.  In python I might do:
>> 
>> print " " * 3
>> 
>> How would I use 'format' to do something similar.
>
> It's quite annoying that there's not something specific for this.
>
> The idiom I always use is based on ~{...~} because it iterates over 
> something.  e.g.,
> [...]
> So if you do:
>
>   (defun spaces (n) (format nil "~V{ ~}" n '(IGNORED)))
>
> you'll get what you want if you want to use FORMAT.
>
> ...  not that I'd advocate FORMAT.  I'd use:
>
>   (make-string 5 :initial-element #\Space)
>
> The only reason to know about the ~{...~} idiom above is if you're already
> doing a FORMAT string with other things in it and you don't want to drop
> out of the FORMAT paradigm in order to get some spaces.

It seems to me that:

    (format t "~V,,,VA" width fill "")

is more readable and better: it gives format an opportunity to do it
more efficiently.

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

"Logiciels libres : nourris au code source sans farine animale."
From: Rob Warnock
Subject: Re: With format, how to print a variable number of spaces
Date: 
Message-ID: <OradndIUWOquqRvZnZ2dnUVZ_q6dnZ2d@speakeasy.net>
Pascal Bourguignon  <···@informatimago.com> wrote:
+---------------
| Kent M Pitman <······@nhplace.com> writes:
| > So if you do:
| >   (defun spaces (n) (format nil "~V{ ~}" n '(IGNORED)))
| > you'll get what you want if you want to use FORMAT.
| > ...  not that I'd advocate FORMAT.  ...
| 
| It seems to me that:
|     (format t "~V,,,VA" width fill "")
| is more readable and better: it gives format an opportunity to do it
| more efficiently.
+---------------

Indeed. But Kent's method raises another interesting possibility,
for when the thing you want to repeat multiple times isn't a
single character:

    > (loop for i below 4 do
        (format t "I'm so~V{ ~A~:*~} happy!~%" i '("very")))
    I'm so happy!
    I'm so very happy!
    I'm so very very happy!
    I'm so very very very happy!
    NIL
    > 


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: =?utf-8?B?VGlhcm7DoW4gw5MgQ29ycsOhaW4=?=
Subject: Re: With format, how to print a variable number of spaces
Date: 
Message-ID: <m2ac8q6ox5.fsf@cascade.local>
I have another 'format' question: say I have a list of key/value
pairs, in an alist:
       '((foo 3) (bar 2) (baz 10))

Can I use format with the list iteration operators to get output like:
    "foo=3;bar=3;baz=10;"?

-- 
Tiarnán
From: Peter Seibel
Subject: Re: With format, how to print a variable number of spaces
Date: 
Message-ID: <m2r722f332.fsf@gigamonkeys.com>
········@yahoo.com (Tiarn�n � Corr�in) writes:

> I have another 'format' question: say I have a list of key/value
> pairs, in an alist:
>        '((foo 3) (bar 2) (baz 10))
>
> Can I use format with the list iteration operators to get output like:
>     "foo=3;bar=3;baz=10;"?

  CL-USER> (format t "~{~{~(~a~)=~a~};~}" '((foo 3) (bar 2) (baz 10)))
  foo=3;bar=2;baz=10;
  NIL

And if, as is often the case, you don't want the list separator (the
#\; in this case) after the last item, you can use this:

  CL-USER> (format t "~{~{~(~a~)=~a~}~^;~}" '((foo 3) (bar 2) (baz 10)))
  foo=3;bar=2;baz=10
  NIL

-Peter

P.S. The ~(...~) around the first ~a is to downcase the symbol name,
on the assumption you're using the default readtable case.

-- 
Peter Seibel           * ·····@gigamonkeys.com
Gigamonkeys Consulting * http://www.gigamonkeys.com/
Practical Common Lisp  * http://www.gigamonkeys.com/book/
From: Rob Warnock
Subject: Re: With format, how to print a variable number of spaces
Date: 
Message-ID: <zNadnf8lGcwPqxvZnZ2dnUVZ_qadnZ2d@speakeasy.net>
Peter Seibel  <·····@gigamonkeys.com> wrote:
+---------------
| ········@yahoo.com (Tiarn�n � Corr�in) writes:
| > ...say I have a list of key/value pairs, in an alist:
| >        '((foo 3) (bar 2) (baz 10))
| > Can I use format with the list iteration operators to get output like:
| >     "foo=3;bar=3;baz=10;"?
| 
|   CL-USER> (format t "~{~{~(~a~)=~a~};~}" '((foo 3) (bar 2) (baz 10)))
|   foo=3;bar=2;baz=10;
|   NIL
+---------------

You only need one iteration level if you use the colon modifier:

    > (format t "~:{~(~a~)=~a;~}" '((foo 3) (bar 2) (baz 10)))
    foo=3;bar=2;baz=10;
    NIL
    > 

+---------------
| And if, as is often the case, you don't want the list separator (the
| #\; in this case) after the last item, you can use this:
| 
|   CL-USER> (format t "~{~{~(~a~)=~a~}~^;~}" '((foo 3) (bar 2) (baz 10)))
|   foo=3;bar=2;baz=10
|   NIL
+---------------

Ditto, mutatis mutandis:

    > (format t "~:{~(~a~)=~a~:^;~}" '((foo 3) (bar 2) (baz 10)))
    foo=3;bar=2;baz=10
    NIL
    > 


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Frank Buss
Subject: Re: With format, how to print a variable number of spaces
Date: 
Message-ID: <1rf03wugqfnrd$.18qx2nfzf05ay$.dlg@40tude.net>
Tiarn�n � Corr�in wrote:

> I have another 'format' question: say I have a list of key/value
> pairs, in an alist:
>        '((foo 3) (bar 2) (baz 10))
> 
> Can I use format with the list iteration operators to get output like:
>     "foo=3;bar=3;baz=10;"?

I'm sure this is possible with some magic format strings, but if you want
that non-format-gurus like me understand your code, you may write it like
this:

(loop for (key value) in '((foo 3) (bar 2) (baz 10)) do
  (format t "~a=~a;" key value))

-- 
Frank Buss, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
From: Wade Humeniuk
Subject: Re: With format, how to print a variable number of spaces
Date: 
Message-ID: <Wr2hg.32147$JX1.15031@edtnps82>
ramza2 wrote:
> How can I print a variable number of spaces.  In python I might do:
> 
> print " " * 3
> 
> How would I use 'format' to do something similar.
> 

Create some "formatter" helpers, e.g.

(defclass repeating-printer-char ()
   ((c :initarg :c)
    (reps :initarg :reps :initform 1)))

(defmethod print-object ((obj repeating-printer-char) stream)
   (with-slots (c reps) obj
     (loop repeat reps do (write-char c stream))))

(defun repeat-char (c &optional (reps 1))
   (make-instance 'repeating-printer-char :c c :reps reps))

(defun test (n)
   (format t "This is a repeat ~A test" (repeat-char #\w n)))

CL-USER 9 > (test 50)
This is a repeat wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww test
NIL

CL-USER 10 > (test 2)
This is a repeat ww test
NIL

CL-USER 11 > (test 1)
This is a repeat w test
NIL

CL-USER 12 >

W
From: Thomas A. Russ
Subject: Re: With format, how to print a variable number of spaces
Date: 
Message-ID: <ymiac8qdug7.fsf@sevak.isi.edu>
"ramza2" <············@gmail.com> writes:

> How can I print a variable number of spaces.  In python I might do:
> 
> print " " * 3
> 
> How would I use 'format' to do something similar.

Using the ~T format directive, with the V parameter.
Using @ makes it always do relative spacing rather than absolute, so
that is probably what you want here.

  (format nil ···@T" 3)  ==>   "   "

What is mildly annoying is that unlike some of the other directives
which have filling, you can't specify a character other than space to
use for the fill.  If ~T took a third parameter, it would be more
friendly:

Hypothetical code:
  (format nil "~v,,··@T" 5)  ==>  "*****"
  (format nil "~v,,·@T" 5 #\.)  ==>  "....."

That would seem to be a solution in keeping with the rest of the format
sublanguage.

Hmmm.  Here is another idea that just occurred to me, although it is
mildly ugly in requiring an empty string argument and it does somewhat
abuse the ~A directive:

  (format nil "~v,A" 4  "")  => "    "

  (format nil "~v,,,vA" 8 #\. "")  => "........"


-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Thomas A. Russ
Subject: Re: With format, how to print a variable number of spaces
Date: 
Message-ID: <ymiejy0dhde.fsf@sevak.isi.edu>
···@sevak.isi.edu (Thomas A. Russ) writes:

> Hmmm.  Here is another idea that just occurred to me, although it is
> mildly ugly in requiring an empty string argument and it does somewhat
> abuse the ~A directive:
> 
>   (format nil "~v,A" 4  "")  => "    "
> 
>   (format nil "~v,,,vA" 8 #\. "")  => "........"

OK, I had a thought to look at a degenerate case of the text
justification operator.  This works like the above but doesn't require
the unaesthetic empty string to be passed as an argument.  It does
require the second ~> directive, though.

  (format nil ···@:<~>" 8)         => "        "
  (format nil "~v,,,v<~>" 8 #\.)    => "........"



-- 
Thomas A. Russ,  USC/Information Sciences Institute