Adding a charcter to the end of a string.

5 views
Skip to first unread message

beo...@my-deja.com

unread,
Oct 31, 2000, 12:52:23 PM10/31/00
to
Hi,
Along the lines of "this can't be as hard as I'm making it" how does one
concate a character to a string? I would like to do something like:

(setf a (make-string 100))
(blah a #\b)
(blah a #\b)
(blah a #\c)

and then have a contain the string "bbc"

I can see how to do it with CONCATENATE but then I end up with

(setf a (make-string 100))
(setf a (concatenate 'string a (make-string 1 :initial-element #\b)))
(setf a (concatenate 'string a (make-string 1 :initial-element #\b)))
(setf a (concatenate 'string a (make-string 1 :initial-element #\c)))

but this just seems too hideous. I also see how one could do it with aref

(setf a (make-string 100))
(setf (aref a 1) #\b)
(setf (aref a 2) #\b)
(setf (aref a 3) #\c)

but I would like not to have to keep track of indices and I'd like not to
worry about that 101st element.

Thanks ever so much. It's been a long time and I didn't work with strings
last time I worked with lisp.

cheers

bruce

Sent via Deja.com http://www.deja.com/
Before you buy.

Barry Margolin

unread,
Oct 31, 2000, 1:21:10 PM10/31/00
to
In article <8tn0sj$30d$1...@nnrp1.deja.com>, <beo...@my-deja.com> wrote:
>Hi,
> Along the lines of "this can't be as hard as I'm making it" how does one
>concate a character to a string? I would like to do something like:
>
>(setf a (make-string 100))
>(blah a #\b)
>(blah a #\b)
>(blah a #\c)
>
>and then have a contain the string "bbc"

Use a vector with a fill pointer, and use vector-push:

(setf a (make-array 100 :type 'character :fill-pointer 0))
(vector-push a #\b)
(vector-push a #\b)
(vector-push a #\c)

If you want it to be able to grow past 100 characters, use :extendable t
when making the array, and use vector-push-extend instead.

--
Barry Margolin, bar...@genuity.net
Genuity, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.

SRS

unread,
Oct 31, 2000, 1:36:51 PM10/31/00
to
In article <8tn0sj$30d$1...@nnrp1.deja.com>,
beo...@my-deja.com wrote:
> Hi,
> Along the lines of "this can't be as hard as I'm making it" how
does one
> concate a character to a string? I would like to do something like:
>
> (setf a (make-string 100))
> (blah a #\b)
> (blah a #\b)
> (blah a #\c)
>
> and then have a contain the string "bbc"
>
> I can see how to do it with CONCATENATE but then I end up with
>
> (setf a (make-string 100))
> (setf a (concatenate 'string a (make-string 1 :initial-element #\b)))
> (setf a (concatenate 'string a (make-string 1 :initial-element #\b)))
> (setf a (concatenate 'string a (make-string 1 :initial-element #\c)))
>
> but this just seems too hideous.

It does indeed, but you do not have to use make-string in this
situation. just coerce the chars you want in to a string using the
function string, and concatenate then to the variable a:

(setf (concatenate 'string a (string #\a)))
(setf (concatenate 'string a (string #\b)))
(setf (concatenate 'string a (string #\c)))

You could also do

(setf a (format nil "~Aa" a))
...and so on

(But if you want a dynamically resizable sequence of letters, why not
use a list, and then coerce it into a string when you need to print it?)

> I also see how one could do it with aref
>
> (setf a (make-string 100))
> (setf (aref a 1) #\b)
> (setf (aref a 2) #\b)
> (setf (aref a 3) #\c)
>
> but I would like not to have to keep track of indices and I'd like
not to
> worry about that 101st element.
>
> Thanks ever so much. It's been a long time and I didn't work with
strings
> last time I worked with lisp.
>
> cheers
>
> bruce
>
> Sent via Deja.com http://www.deja.com/
> Before you buy.
>

-- SRS

John Clonts

unread,
Oct 31, 2000, 3:09:01 PM10/31/00
to
In article <8tn3g2$5g9$1...@nnrp1.deja.com>,

SRS <sr...@my-deja.com> wrote:
> In article <8tn0sj$30d$1...@nnrp1.deja.com>,
> beo...@my-deja.com wrote:
[snip]

>
> (But if you want a dynamically resizable sequence of letters, why not
> use a list, and then coerce it into a string when you need to print
it?)
>

By coerce I guess you mean

(concatenate 'string '(#\a #\b #c)) ==> "abc"

But I have a different question: How to "coerce" a list of symbols to
append them into a string:

(setf aa '(a bc de f))
(list-of-symbols-to-string aa) ==> "abcdef"

This is how I did it:
(defun list-of-symbols-to-string (list)
(apply #'concat-strings (mapcar #'string list)))

(defun concat-strings (&rest r)
(eval (append '(concatenate 'string ) r)))

But I really wanted to do without the eval, rather something like:
(defun concat-strings (&rest r)
(concatenate 'string @r))

Thanks,
John

Erik Naggum

unread,
Oct 31, 2000, 3:32:01 PM10/31/00
to
* John Clonts <joh...@my-deja.com>

| But I have a different question: How to "coerce" a list of symbols
| to append them into a string:

By not getting into this fix to begin with. (Why are they symbols?)

| (setf aa '(a bc de f))
| (list-of-symbols-to-string aa) ==> "abcdef"
|
| This is how I did it:
| (defun list-of-symbols-to-string (list)
| (apply #'concat-strings (mapcar #'string list)))
|
| (defun concat-strings (&rest r)
| (eval (append '(concatenate 'string ) r)))
|
| But I really wanted to do without the eval, rather something like:
| (defun concat-strings (&rest r)
| (concatenate 'string @r))

(apply #'concatenate 'string (mapcar #'string list))

If you have a Scheme background (where apply takes two arguments),
you could have consed 'string onto the list of arguments, too.

#:Erik
--
Does anyone remember where I parked Air Force One?
-- George W. Bush

Rainer Joswig

unread,
Oct 31, 2000, 4:43:45 PM10/31/00
to
In article <8tn3g2$5g9$1...@nnrp1.deja.com>, SRS <sr...@my-deja.com>
wrote:

> It does indeed, but you do not have to use make-string in this


> situation. just coerce the chars you want in to a string using the
> function string, and concatenate then to the variable a:
>
> (setf (concatenate 'string a (string #\a)))
> (setf (concatenate 'string a (string #\b)))
> (setf (concatenate 'string a (string #\c)))

>
> (setf (concatenate 'string a (string #\a)))

Which would be really:

(setf a (concatenate 'string a (string #\a)))

Also one does not concatenate the string to a variable.
You are concatenating the value of A (-> a string) and the
value of (STRING #\a) (-> also a string) to a new (!!) string.

Common Lisp also has the idea of adjustable array (which
can change the size) and arrays with a fill-pointer.
Adding elements to an array with a FILL-POINTER
is done via VECTOR-PUSH. If you want to use the feature
of an adjustable array, VECTOR-PUSH-EXTEND is your
friend:

? (setf a (make-array 10
:element-type 'character
:adjustable t
:fill-pointer 0))
""

? (vector-push-extend #\a a)
0

? a
"a"

? (vector-push-extend #\b a)
1

? a
"ab"
? (vector-push-extend #\c a)
2

? a
"abc"

Another way cons up strings is to use a special stream:

(with-output-to-string (stream)
(princ #\a stream)
(princ #\b stream)
(princ #\c stream))

or

(with-output-to-string (*standard-output*)
(princ #\a)
(princ #\b)
(princ #\c))

--
Rainer Joswig, Hamburg, Germany
Email: mailto:jos...@corporate-world.lisp.de
Web: http://corporate-world.lisp.de/

Thomas A. Russ

unread,
Oct 31, 2000, 4:43:58 PM10/31/00
to

John Clonts <joh...@my-deja.com> writes:

> But I have a different question: How to "coerce" a list of symbols to
> append them into a string:

A general solution could be written using format:

(defun list-of-whatever-to-string (list)
(format nil "~{~A~}" list)
)

Hmmm. By an amazing coincidence the body of the function happens to be
the same length as its name.

Note: Depending on how you want the output to appear in the case of
mixed case symbol names, different packages, etc. you might want to use
~S instead of ~A.

--
Thomas A. Russ, USC/Information Sciences Institute t...@isi.edu

Rob Warnock

unread,
Oct 31, 2000, 11:57:21 PM10/31/00
to
Erik Naggum <er...@naggum.net> wrote:
+---------------

| (apply #'concatenate 'string (mapcar #'string list))
|
| If you have a Scheme background (where apply takes two arguments),
| you could have consed 'string onto the list of arguments, too.
+---------------

Erik, just as Lisp has evolved beyond the outdated concepts of
"interpreter/slow/etc." and Common Lisp has evolved beyond CLtL1,
Scheme too has made *some* progress over its life, and in fact has
had multi-arg "apply" since at least 1986 with the release of R3RS.

Granted, in R3RS and R4RS the two-arg form was called an "essential
procedure" and the multi-arg form was just a "procedure", but by the
time of the IEEE Scheme Standard in 1991 (and in R5RS today), this
distinction had vanished:

(apply proc arg1 ... args)

Proc must be a procedure and args must be a list. Calls proc
with the elements of the list (append (list arg1 ...) args)
as the actual arguments.

For example:

> (apply vector 1 2 3 '(4 5 6))
#(1 2 3 4 5 6)
> (apply string-append (map string '(#\a #\c #\e) '(#\b #\d #\f)))
"abcdef"
>


-Rob

-----
Rob Warnock, 31-2-510 rp...@sgi.com
Network Engineering http://reality.sgi.com/rpw3/
Silicon Graphics, Inc. Phone: 650-933-1673
1600 Amphitheatre Pkwy. PP-ASEL-IA
Mountain View, CA 94043

John Clonts

unread,
Nov 1, 2000, 12:16:38 AM11/1/00
to
Erik Naggum wrote:
>
> * John Clonts <joh...@my-deja.com>
> | But I have a different question: How to "coerce" a list of symbols
> | to append them into a string:
>
> By not getting into this fix to begin with. (Why are they symbols?)
>

Hmm, good point.

> | (setf aa '(a bc de f))
> | (list-of-symbols-to-string aa) ==> "abcdef"
> |
> | This is how I did it:
> | (defun list-of-symbols-to-string (list)
> | (apply #'concat-strings (mapcar #'string list)))
> |
> | (defun concat-strings (&rest r)
> | (eval (append '(concatenate 'string ) r)))
> |
> | But I really wanted to do without the eval, rather something like:
> | (defun concat-strings (&rest r)
> | (concatenate 'string @r))
>
> (apply #'concatenate 'string (mapcar #'string list))
>

Perfect, thanks. I guess I now better understand "spreadable argument
list designator".

Cheers,
John

beo...@my-deja.com

unread,
Nov 1, 2000, 3:46:19 AM11/1/00
to
Thanks to everyone!

Erik Naggum

unread,
Nov 1, 2000, 9:10:18 AM11/1/00
to
* Rob Warnock

| Erik, just as Lisp has evolved beyond the outdated concepts of
| "interpreter/slow/etc." and Common Lisp has evolved beyond CLtL1,
| Scheme too has made *some* progress over its life, and in fact has
| had multi-arg "apply" since at least 1986 with the release of R3RS.

What? You mean it's time for _me_ to evolve, too? I thought I
could avoid that, but if my .project ("immortality in our lifetime")
has any hopes, I'd better get used to it.

Seriously, though, I have always disliked the separation between
essential and non-essential procedueres in Scheme, so if it has
vanished as a whole, I'm as delighted as I can be when I don't like
Scheme to begin with. If it is only gone for apply, well, it's a
step in the right direction.

Thanks for the update.

Marco Antoniotti

unread,
Nov 1, 2000, 10:14:42 AM11/1/00
to

rp...@rigden.engr.sgi.com (Rob Warnock) writes:

> Erik Naggum <er...@naggum.net> wrote:
> +---------------
> | (apply #'concatenate 'string (mapcar #'string list))
> |
> | If you have a Scheme background (where apply takes two arguments),
> | you could have consed 'string onto the list of arguments, too.
> +---------------
>
> Erik, just as Lisp has evolved beyond the outdated concepts of
> "interpreter/slow/etc." and Common Lisp has evolved beyond CLtL1,
> Scheme too has made *some* progress over its life, and in fact has
> had multi-arg "apply" since at least 1986 with the release of R3RS.
>
> Granted, in R3RS and R4RS the two-arg form was called an "essential
> procedure" and the multi-arg form was just a "procedure", but by the
> time of the IEEE Scheme Standard in 1991 (and in R5RS today), this
> distinction had vanished:
>
> (apply proc arg1 ... args)
>
> Proc must be a procedure and args must be a list. Calls proc
> with the elements of the list (append (list arg1 ...) args)
> as the actual arguments.
>
> For example:
>
> > (apply vector 1 2 3 '(4 5 6))
> #(1 2 3 4 5 6)
> > (apply string-append (map string '(#\a #\c #\e) '(#\b #\d #\f)))
> "abcdef"
> >

All true, but Scheme does not have arrays with fill pointers. :)
Which is what is most useful in this case.

Cheers

--
Marco Antoniotti =============================================================
NYU Bioinformatics Group tel. +1 - 212 - 998 3488
719 Broadway 12th Floor fax +1 - 212 - 995 4122
New York, NY 10003, USA http://galt.mrl.nyu.edu/valis
Like DNA, such a language [Lisp] does not go out of style.
Paul Graham, ANSI Common Lisp

Rob Warnock

unread,
Nov 5, 2000, 11:51:17 PM11/5/00
to
[Sorry to have taken so long for this reply...]

Erik Naggum <er...@naggum.net> wrote:
+---------------

| * Rob Warnock
| | Scheme... has had had multi-arg "apply" since at least 1986... R3RS.
...


| Seriously, though, I have always disliked the separation between
| essential and non-essential procedueres in Scheme, so if it has
| vanished as a whole, I'm as delighted as I can be when I don't like
| Scheme to begin with. If it is only gone for apply, well, it's a
| step in the right direction.

+---------------

Well, I've got some good news, and some bad news... ;-}

IEEE Standard Scheme [1991] did indeed erase the "essential/non-essential"
distinction completely, but... as of R5RS "it's BAAAAaaaack", in the form
of "primitive", "library", and "optional" syntax & procedures:

The report is now a superset of the IEEE standard for Scheme [so]...
The classification of features as essential or inessential has
been removed. There are now three classes of built-in procedures:
primitive, library, and optional. The optional procedures are
load, with-input-from-file, with-output-to-file, transcript-on,
transcript-off, and interaction-environment, and - and / with
more than two arguments. None of these are in the IEEE standard.

One might reasonably question "load" being optional, but since "eval" is
now required [since everything in R5RS that is not "optional" is required],
"load" can be synthesized from other primitives.

Likewise, "with-input-from-file" & "with-output-to-file" can be emulated
with wrappers [and in any event are dangerous in the presence of errors,
since R5RS makes no guarantees about file closure on error -- "If an
escape procedure is used to escape from the continuation of these
procedures, their behavior is implementation dependent" -- whereas in
one's own implementation one can at least choose the desired behavior,
using "dynamic-wind" (except: see last item below!)].

As for the primitive/library distinction:

1.3.1 Primitive, library, and optional features
...
To aid in understanding and implementing Scheme, some features
are marked as library. These can be easily implemented in terms
of the other, primitive, features. They are redundant in the
strict sense of the word, but they capture common patterns of
usage, and are therefore provided as convenient abbreviations.

Since R5RS has "syntax-rules"-style hygenic macros as a required
primitive feature, macros can be used to implement such "library
syntax" as cond/case/and/or/let/let*/letrec/begin/do/delay, &c.

Finally, as mentioned above, "dynamic-wind" is now required, which at
least sets the stage for decent exception handling, but unfortunately
errors are *not* yet specified in terms of callinng a [top-level]
continuation, so there's still no guarantee that an error will even
invoke the "out" limb of a "dynamic-wind" at all!! (*sigh*)

Kent M Pitman

unread,
Nov 6, 2000, 1:12:58 AM11/6/00
to
rp...@rigden.engr.sgi.com (Rob Warnock) writes:

> Likewise, "with-input-from-file" & "with-output-to-file" can be emulated
> with wrappers [and in any event are dangerous in the presence of errors,
> since R5RS makes no guarantees about file closure on error -- "If an
> escape procedure is used to escape from the continuation of these
> procedures, their behavior is implementation dependent" -- whereas in
> one's own implementation one can at least choose the desired behavior,
> using "dynamic-wind" (except: see last item below!)].

No, this is orthogonal to dynamic-wind. Dynamic-wind is how you implement
process switching, but this isn't the problem for with-input-from-file that
Scheme has. The problem there is functions that return more than once,
and in those cases only the GC knows whether someone is holding a pointer
to something that might be reinvoked. Dynamic wind doesn't run
unwind-protects like with-input-from-file would set up, but that doesn't
mean there isn't a crisis if other kinds of escape procedures are run.
A consequence is that files only get closed when the gc is good and ready,
and can't be properly closed [as a CL user would expect] reliably upon the
point of escape.

> Finally, as mentioned above, "dynamic-wind" is now required, which at
> least sets the stage for decent exception handling, but unfortunately
> errors are *not* yet specified in terms of callinng a [top-level]
> continuation, so there's still no guarantee that an error will even
> invoke the "out" limb of a "dynamic-wind" at all!! (*sigh*)

Uh, I'm not clear on this but would have to look harder. It's not obvious
to me why dynamic-wind can't cooperate neatly with other unwinds, unless
it's just a typo in the spec [which I don't have handy as I write this].


Boris Schaefer

unread,
Nov 7, 2000, 3:00:00 AM11/7/00
to
Kent M Pitman <pit...@world.std.com> writes:

| No, this is orthogonal to dynamic-wind. Dynamic-wind is how you
| implement process switching, but this isn't the problem for
| with-input-from-file that Scheme has. The problem there is
| functions that return more than once, and in those cases only the GC
| knows whether someone is holding a pointer to something that might
| be reinvoked. Dynamic wind doesn't run unwind-protects like
| with-input-from-file would set up, but that doesn't mean there isn't
| a crisis if other kinds of escape procedures are run. A consequence
| is that files only get closed when the gc is good and ready, and
| can't be properly closed [as a CL user would expect] reliably upon
| the point of escape.

Do I understand it correctly that you mean something like:

(define continuation #f)

(with-input-from-file
"foo"
(lambda ()
(if (call-with-current-continuation
(lambda (cc)
(set! continuation cc)
#t))
'do-nothing
(read-char))))

(continuation #f)

or are you talking about something else?

--
bo...@uncommon-sense.net - <http://www.uncommon-sense.net/>

I think a relationship is like a shark. It has to constantly move forward
or it dies. Well, what we have on our hands here is a dead shark.
-- Woody Allen

Reply all
Reply to author
Forward
0 new messages