Hi all,
This may seem trivial to you "old-timers"; but I have a problem in line 4 of
the following code. I can see why I get an "Undefined variable"-error but
how do I make the inner str-variable visible to 'let'? It works fine in
lines 2 and 3.
1: (defun word (str)
2: (let ((str (string-left-trim '(#\Space) str)))
;Remove any leading spaces
3: (let ((spc (position #\Space str)))
;Find first trailing space - if any (Test for NIL)
4: (let ((str (str :end (- spc 1))))
;Isolate word before any trailing space(s)
5: (format t "~a : ~a" spc str)))))
Can anybody please tell me, what to do?
Is there a better way of isolating a word, retaining case?
Thanks in advance
Mogens
> (let ((str (str :end (- spc 1))))
The first str here is a variable.
The second str is a function (first argument is :end ... second
argument is (- spc 1))
Since there is no str function, you have a problem :)
>Can anybody please tell me, what to do?
>Is there a better way of isolating a word, retaining case?
Yes. In fact, the right way to do this is so easy that you probably
shouldn't even write this function, unless you prefer shorter function
names :)
(defun word (str)
(read-from-string str))
>>Can anybody please tell me, what to do?
>>Is there a better way of isolating a word, retaining case?
>Yes. In fact, the right way to do this is so easy that you probably
>shouldn't even write this function, unless you prefer shorter function
>names :)
>(defun word (str)
> (read-from-string str))
I forgot. You don't just want to isolate the word. You also want to
print it. Try this:
(defun word (str)
(format t "~a : ~a" (read-from-string str) str))
Hi Eric,
Thank you very much for your prompt response.
However, read-from-string gives me a problem with punctuation-marks; so
maybe I should use read-byte or read-char to catch escaped characters.
Eric Lavigne wrote:
>>>Can anybody please tell me, what to do?
>>>Is there a better way of isolating a word, retaining case?
>
>>Yes. In fact, the right way to do this is so easy that you probably
>>shouldn't even write this function, unless you prefer shorter function
>>names :)
>
>>(defun word (str)
>> (read-from-string str))
>
> I forgot. You don't just want to isolate the word. You also want to
> print it. Try this:
>
> (defun word (str)
> (format t "~a : ~a" (read-from-string str) str))
>Thank you very much for your prompt response.
>However, read-from-string gives me a problem with punctuation-marks
How should punctuation marks be treated? The following function grabs a
substring starting with the first non-space and continuing until it
encounters another space (or end of string). Then it removes any
non-alphabetic characters (such as punctuation) and prints the result.
(defun word (string)
(let ((string (string-left-trim '(#\Space) string)))
(let ((space (position #\Space string)))
(let ((string (subseq string 0 space)))
(format t "~a : ~a"
space
(remove-if-not #'alpha-char-p
string))))))
Hi Eric,
Thank you for your answer. It was the solution I was trying to obtain.
Best wishes,
Mogens
Eric Lavigne wrote:
>>Thank you very much for your prompt response.
>>However, read-from-string gives me a problem with punctuation-marks
>
> How should punctuation marks be treated? The following function grabs a
> substring starting with the first non-space and continuing until it
> encounters another space (or end of string). Then it removes any
> non-alphabetic characters (such as punctuation) and prints the result.
>
> (defun word (string)
> (let ((string (string-left-trim '(#\Space) string)))
> (let ((space (position #\Space string)))
> (let ((string (subseq string 0 space)))
> (format t "~a : ~a"
> space
> (remove-if-not #'alpha-char-p
> string))))))
Eric Lavigne wrote:
> Yes. In fact, the right way to do this is so easy that you probably
> shouldn't even write this function, unless you prefer shorter function
> names :)
>
> (defun word (str)
> (read-from-string str))
but you have to modify the readtable to preserve whitespace. Perhaps the OP
means this (fixing the "str" bug, better names for Lisp (in Lisp you
usually use verbose names) and standard formatting) :
(defun word (string)
(let ((string (string-left-trim '(#\Space) string)))
(let ((space (position #\Space string)))
(let ((string (subseq string 0 space)))
(format t "~a : ~a" space string)))))
If you want to extract all words, it could be written like this:
(defun word (string &key (start 0))
(let ((word-start (position-if-not #'(lambda (c) (char= c #\Space))
string
:start start)))
(unless word-start (setf word-start 0))
(let ((word-end (position #\Space string :start word-start)))
(values (subseq string word-start word-end) word-end))))
(defun words (string &key (start 0))
(multiple-value-bind (word end) (word string :start start)
(format t "~a~%" word)
(when end (words string :start end))))
CL-USER > (word "first word")
"first"
5
CL-USER > (words "Hello Lisp!")
Hello
Lisp!
NIL
--
Frank Bu�, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
Hi Frank,
Thank you for your input. It seems to be what I was looking for. I will have
a closer look at it and incorporate it into my small exercise.
Thanks again,
Mogens
Frank Buss wrote:
> Eric Lavigne wrote:
>
>> Yes. In fact, the right way to do this is so easy that you probably
>> shouldn't even write this function, unless you prefer shorter function
>> names :)
>>
>> (defun word (str)
>> (read-from-string str))
>
> but you have to modify the readtable to preserve whitespace. Perhaps the
> OP means this (fixing the "str" bug, better names for Lisp (in Lisp you
> usually use verbose names) and standard formatting) :
>
> (defun word (string)
> (let ((string (string-left-trim '(#\Space) string)))
> (let ((space (position #\Space string)))
> (let ((string (subseq string 0 space)))
> (format t "~a : ~a" space string)))))
>
> If you want to extract all words, it could be written like this:
>
> (defun word (string &key (start 0))
> (let ((word-start (position-if-not #'(lambda (c) (char= c #\Space))
> string
> :start start)))
> (unless word-start (setf word-start 0))
> (let ((word-end (position #\Space string :start word-start)))
> (values (subseq string word-start word-end) word-end))))
>
> (defun words (string &key (start 0))
> (multiple-value-bind (word end) (word string :start start)
> (format t "~a~%" word)
> (when end (words string :start end))))
>
> CL-USER > (word "first word")
> "first"
> 5
>
> CL-USER > (words "Hello Lisp!")
> Hello
> Lisp!
> NIL
>
Mogens Neupart asked about trimming spaces to get at a word
in a string.
1: (defun word (str)
2: (let ((str (string-left-trim '(#\Space) str)))
;Remove any leading spaces
3: (let ((spc (position #\Space str)))
;Find first trailing space - if any (Test for NIL)
4: (let ((str (str :end (- spc 1))))
;Isolate word before any trailing space(s)
5: (format t "~a : ~a" spc str)))))
STRING-LEFT-TRIM doesn't work quite as nicely as usual here
because you compute the position relative to the trimmed
string. When you throw away the trimmed string the meaning
of the position value becomes opaque
Try
(defun character-predicate (target-char)
(lambda(test-char)
(char= target-char test-char)))
(defun first-word (string)
(let* ((initial-character (position-if-not (character-predicate #\Space)
string))
(terminating-space (position #\Space string
:start initial-character)))
(list terminating-space
(subseq string
initial-character
terminating-space))))
(defun word (string)
(format t "~{~A~^ : ~}" (first-word string)))
(first-word " foo bar") => (6 "foo")
i.e. first-word returns a list.
The REPL prints the list.
The REPL quotes strings when it prints them.
CL-USER(8): (word " foo bar")
6 : foo <= word printed this with format ~A so no quotes
NIL <= the REPL printed the NIL return value
CL-USER(9):
Play with character-predicate like this:
CL-USER(18): (funcall (character-predicate #\a) #\a)
T
CL-USER(19): (funcall (character-predicate #\a) #\b)
NIL
CL-USER(20): (mapcar (character-predicate #\b)
'(#\a #\b #\c))
(NIL T NIL)
CL-USER(21): (map 'list (character-predicate #\b)
"abc")
(NIL T NIL)
Alan Crowe
Edinburgh
Scotland
Hi Alan,
Thank you for your example code. I will certainly try to experiment with it.
Frank Buss' posting contains a good solution to my problem; but as a
beginning Lisper I am keen to see different examples, so thanks again.
Mogens
Alan Crowe wrote:
> Mogens Neupart asked about trimming spaces to get at a word
> in a string.
>
> 1: (defun word (str)
> 2: (let ((str (string-left-trim '(#\Space) str)))
> ;Remove any leading spaces
>
> 3: (let ((spc (position #\Space str)))
> ;Find first trailing space - if any (Test for NIL)
>
> 4: (let ((str (str :end (- spc 1))))
> ;Isolate word before any trailing space(s)
>
> 5: (format t "~a : ~a" spc str)))))
>
> STRING-LEFT-TRIM doesn't work quite as nicely as usual here
> because you compute the position relative to the trimmed
> string. When you throw away the trimmed string the meaning
> of the position value becomes opaque
>
> Try
>
> (defun character-predicate (target-char)
> (lambda(test-char)
> (char= target-char test-char)))
>
> (defun first-word (string)
> (let* ((initial-character (position-if-not (character-predicate
> #\Space)
> string))
> (terminating-space (position #\Space string
> :start initial-character)))
> (list terminating-space
> (subseq string
> initial-character
> terminating-space))))
>
> (defun word (string)
> (format t "~{~A~^ : ~}" (first-word string)))
>
> (first-word " foo bar") => (6 "foo")
>
> i.e. first-word returns a list.
> The REPL prints the list.
> The REPL quotes strings when it prints them.
>
> CL-USER(8): (word " foo bar")
> 6 : foo <= word printed this with format ~A so no quotes
> NIL <= the REPL printed the NIL return value
> CL-USER(9):
>
> Play with character-predicate like this:
>
> CL-USER(18): (funcall (character-predicate #\a) #\a)
> T
> CL-USER(19): (funcall (character-predicate #\a) #\b)
> NIL
> CL-USER(20): (mapcar (character-predicate #\b)
> '(#\a #\b #\c))
> (NIL T NIL)
> CL-USER(21): (map 'list (character-predicate #\b)
> "abc")
> (NIL T NIL)
>
> Alan Crowe
> Edinburgh
> Scotland
From: Thomas A. Russ
Subject: Re: Newbie: Please, help with undefined variable
Date:
Message-ID: <ymi3brquoj2.fsf@sevak.isi.edu>
Mogens Neupart <·······@pc.dk> writes:
>
> Hi all,
>
> This may seem trivial to you "old-timers"; but I have a problem in line 4 of
> the following code. I can see why I get an "Undefined variable"-error but
> how do I make the inner str-variable visible to 'let'? It works fine in
> lines 2 and 3.
>
> 1: (defun word (str)
> 2: (let ((str (string-left-trim '(#\Space) str)))
> ;Remove any leading spaces
>
> 3: (let ((spc (position #\Space str)))
> ;Find first trailing space - if any (Test for NIL)
>
> 4: (let ((str (str :end (- spc 1))))
^
Are you missing a function here, like subseq?
> ;Isolate word before any trailing space(s)
>
> 5: (format t "~a : ~a" spc str)))))
>
> Can anybody please tell me, what to do?
Well, for starters, if you want to reuse the same variable name, I find
it much less confusing to use SETQ rather than rebinding it.
> Is there a better way of isolating a word, retaining case?
This seems to be a pretty standard method of doing what you want.
--
Thomas A. Russ, USC/Information Sciences Institute
Hi Thomas,
Thank you for your answer. I am pleased to hear that I have used some sort
of standard for for writing my exercise. In the thread posted by Frank Buss
I learned that I did indeed miss the subseq function. The same posting gave
me some ideas of how to extend my exercise.
Thanks again,
Mogens
Thomas A. Russ wrote:
> Mogens Neupart <·······@pc.dk> writes:
>
>>
>> Hi all,
>>
>> This may seem trivial to you "old-timers"; but I have a problem in line 4
>> of the following code. I can see why I get an "Undefined variable"-error
>> but how do I make the inner str-variable visible to 'let'? It works fine
>> in lines 2 and 3.
>>
>> 1: (defun word (str)
>> 2: (let ((str (string-left-trim '(#\Space) str)))
>> ;Remove any leading spaces
>>
>> 3: (let ((spc (position #\Space str)))
>> ;Find first trailing space - if any (Test for NIL)
>>
>> 4: (let ((str (str :end (- spc 1))))
> ^
> Are you missing a function here, like subseq?
>
>> ;Isolate word before any trailing space(s)
>>
>> 5: (format t "~a : ~a" spc str)))))
>>
>> Can anybody please tell me, what to do?
>
> Well, for starters, if you want to reuse the same variable name, I find
> it much less confusing to use SETQ rather than rebinding it.
>
>> Is there a better way of isolating a word, retaining case?
>
> This seems to be a pretty standard method of doing what you want.
>
>