From: Thomas A. Russ on
mike <mpheasant(a)gmail.com> writes:

> Thanks everyone for the different solutions.
> In this case I wasnt clear enough that I'm writing something like an
> awk script to reformat tab-delimited input, so need an actual tab.
....
> In the end I guess my problem is just how to embed a tab char into the
> format string using an 'escape sequence'. (Embedding the actual tab
> char in the source isnt appealing.) This seems to work ok:

Well, it may not be appealing to you, but inserting the literal
character into the string is the easy Lisp Way(tm) to do it. It is just
like when you want to have a literal newline character (sorry Pascal) in
a constant string. The way you do that is to literally insert the
newline character:

(defvar *a-multi-line-string*
"This is a string
that extends over several
lines in lisp.")

(defvar *a-single-line-string*
"This is a string\n on one line with odd\n characters in it.")


--
Thomas A. Russ, USC/Information Sciences Institute
From: Kyle M on
On Nov 2, 4:52 pm, mike <mpheas...(a)gmail.com> wrote:
> Thanks everyone for the different solutions.
> In this case I wasnt clear enough that I'm writing something like an
> awk script to reformat tab-delimited input, so need an actual tab.
> Thanks to Vassil for pointing out the different results from
> (reduce ... (format nil ...)) and (reduce ... (format t ...)), I didnt
> know that either.
>
> In the end I guess my problem is just how to embed a tab char into the
> format string using an 'escape sequence'. (Embedding the actual tab
> char in the source isnt appealing.) This seems to work ok:
>
> (format t (concatenate 'string "~{~a~^" (string #\Tab) "~}~%") '(1 2
> 3))
>
> Otherwise the ~/ is a good way to go.
>
> I thought there would have been an easier way to insert control chars
> into the format string; seems wierd that there is a special case for ~
> %, and that recognising codes like #\Tab wouldnt be in the spec.
>
> Cheers
>
> M
>
> On Nov 3, 4:48 am, Kyle M <kyle...(a)gmail.com> wrote:
>
> > On Nov 2, 1:29 pm, Carl Taylor <carltay...(a)att.net> wrote:
>
> > > On Nov 2, 2:00 am, mike <mpheas...(a)gmail.com> wrote:
>
> > > > Hi
>
> > > > Formatting a list as a comma-delimited string is easy;
>
> > > > (format nil "~{~a~^,~}" '(1 2 3))  =>  "1,2,3"
>
> > > > How do i do the same (SBCL) but with tab characters in the output?
> > > > It must be simple but I've tried a ton of different things.
>
> > > Use the ~n@T directive in the format string where n is an integer
> > > to specify the width of the desired tab.
>
> > > CL-USER 7 > (format nil "~{~a~^~5@T~}" '(1 2 3))
> > > "1     2     3"
>
> > > Carl Taylor
>
> > The ~T is not equivalent to #\Tab. But like Madhu said earlier, it
> > depends on your editor. Some may treat #\Tab as just some number of
> > spaces, so it wouldn't matter anyway.
>
>

I think you've found a good way to do it using concatenate. For the
record, there are all kinds of ways of doing this without using the ~
{~} format iteration, not just reduce like I initially suggested. It's
terribly boring, and probably won't attract everyone, but having
written a few files out, I'd rather go with what I consider to be
simple:

(format ostream "~A" (first list))
(dolist (x (rest list))
(format ostream "~C~A" #\tab x))

And then if you wanted that in string form you could wrap this guy
around it.

(with-output-to-string (ostream) ...)

Kyle
From: Don Geddis on
mike <mpheasant(a)gmail.com> wrote on Mon, 2 Nov 2009 :
> In this case I wasnt clear enough that I'm writing something like an
> awk script to reformat tab-delimited input, so need an actual tab.
> (format t (concatenate 'string "~{~a~^" (string #\Tab) "~}~%") '(1 2 3))

Everything goes better with LOOP:

(loop
for first-time? = t then nil
for element in '(1 2 3)
unless first-time? do (format t "~A" #\tab)
do (format t "~A" element) )

YMMV.

More wordy than a constructed FORMAT string. But clearer? I suppose it
depends on what you're used to, whether you spend more time with LOOP
or with FORMAT control strings.

(I suspect the final compiled code isn't all that different.)

-- Don
_______________________________________________________________________________
Don Geddis http://don.geddis.org/ don(a)geddis.org
From: John Thingstad on
The Mon, 02 Nov 2009 10:48:18 -0800, Kyle M wrote:

> On Nov 2, 1:29 pm, Carl Taylor <carltay...(a)att.net> wrote:
>> On Nov 2, 2:00 am, mike <mpheas...(a)gmail.com> wrote:
>>
>> > Hi
>>
>> > Formatting a list as a comma-delimited string is easy;
>>
>> > (format nil "~{~a~^,~}" '(1 2 3))  =>  "1,2,3"
>>
>> > How do i do the same (SBCL) but with tab characters in the output? It
>> > must be simple but I've tried a ton of different things.
>>
>> Use the ~n@T directive in the format string where n is an integer to
>> specify the width of the desired tab.
>>
>> CL-USER 7 > (format nil "~{~a~^~5@T~}" '(1 2 3)) "1     2     3"
>>
>> Carl Taylor
>
> The ~T is not equivalent to #\Tab. But like Madhu said earlier, it
> depends on your editor. Some may treat #\Tab as just some number of
> spaces, so it wouldn't matter anyway.

Another way is to modify the reader to accept \n \r \t etc.. as C does.
From a printf function I wrote long ago..

(I think Gareth McCaughan originally suggested this.)

(defvar *string-escape-character* #\\)
(defvar *string-escape-table*
;; built with LIST and CONS so it's legal to modify it
(list
(cons #\t #\Tab)
(cons #\n #\Newline)
(cons #\r #\Return)
...))
(defvar *escaped-string-delimiters*
(list #\" #\'))
(set-dispatch-macro-character #\# #\E
(lambda (stream sub-char infix-arg)
(declare (ignore sub-char infix-arg))
(let ((delimiter (read-char stream))
(escaped nil))
(assert (member delimiter *escaped-string-delimiters*))
(coerce (loop for next-char = (read-char stream) nconc
(cond
(escaped
(progn (setf escaped nil)
(list (or (cdr (assoc next-char *string-escape-table*))
next-char))))
((char= next-char delimiter)
(loop-finish))
((char= next-char *string-escape-character*)
(setf escaped t)
nil)
(t (list next-char))))
'string))))

(format nil #E"~{~a~^\t~}" '(1 2 3))

This would be better if you do this type of thing a lot..


Another way is to modify the reader to accept \n \r \t as C does.
From a printf function I wrote long ago..

(I think Gareth McCaughan originally suggested this.)

(defvar *string-escape-character* #\\)
(defvar *string-escape-table*
;; built with LIST and CONS so it's legal to modify it
(list
(cons #\t #\Tab)
(cons #\n #\Newline)
(cons #\r #\Return)
...))
(defvar *escaped-string-delimiters*
(list #\" #\'))
(set-dispatch-macro-character #\# #\E
(lambda (stream sub-char infix-arg)
(declare (ignore sub-char infix-arg))
(let ((delimiter (read-char stream))
(escaped nil))
(assert (member delimiter *escaped-string-delimiters*))
(coerce (loop for next-char = (read-char stream) nconc
(cond
(escaped
(progn (setf escaped nil)
(list (or (cdr (assoc next-char *string-escape-table*))
next-char))))
((char= next-char delimiter)
(loop-finish))
((char= next-char *string-escape-character*)
(setf escaped t)
nil)
(t (list next-char))))
'string))))

(format nil #E"~{~a~^\t~}" '(1 2 3))

This would be better if you do this type of thing a lot..

--
John Thingstad
First  |  Prev  | 
Pages: 1 2 3
Prev: faster?
Next: Article about lisp and array languages