From: Yossarian
Subject: Newbie lisp problem: string to list of strings separated by space
Date:
Message-ID: <e0g57j$r75$1@gaudi2.UGent.be>
Hi,
I am trying to write a very simple function that accepts a string as
input, and that returns a list of strings as output, having a seperate
list item for every substring without a space.
Example:
input = "something very odd"
output = ("something" "very" "odd")
I tried to do this with the following function, but I can't understand
why it is not working.
(defun parse(a)
(setq pos (or (position #\space a) -1) )
(cond ((= pos -1) (list a))
((> pos -1) (append
(parse (subseq a 0 pos))
(parse (subseq a (+ pos 1) (length a)))))))
Any comment is welcome!
Regards,
Wouter
From: John Landahl
Subject: Re: Newbie lisp problem: string to list of strings separated by space
Date:
Message-ID: <87wteban4w.fsf@mobile.landahl.org>
Yossarian <·········@aixioma.net> writes:
> I am trying to write a very simple function that accepts a string as
> input, and that returns a list of strings as output, having a
> seperate list item for every substring without a space.
It seems we all write one of these eventually. Here's one I came up
with a while back:
(defun string-split (split-string string)
"Returns a list containing items in 'string' split from
occurrences of 'split-string'."
(loop with l = (length split-string)
for n = 0 then (+ pos l)
for pos = (search split-string string :start2 n)
if pos collect (subseq string n pos)
else collect (subseq string n)
while pos))
CL-USER> (string-split " " "yeah yeah yeah")
("yeah" "yeah" "yeah")
Also splits on strings of any length:
CL-USER> (string-split "..." "yes...yes...yes")
("yes" "yes" "yes")
But then you're much better off getting CL-PPCRE and using its SPLIT
function, which is far more powerful:
CL-USER> (cl-ppcre:split "\\s" "yeah yeah yeah")
("yeah" "yeah" "yeah")
CL-USER> (cl-ppcre:split "[,:;]" "hello,there:sir")
("hello" "there" "sir")
--
John Landahl <····@landahl.org>
http://landahl.org/john
Yossarian <·········@aixioma.net> writes:
> Hi,
>
> I am trying to write a very simple function that accepts a string as
> input, and that returns a list of strings as output, having a seperate
> list item for every substring without a space.
>
> Example:
> input = "something very odd"
> output = ("something" "very" "odd")
>
> I tried to do this with the following function, but I can't understand
> why it is not working.
>
> (defun parse(a)
> (setq pos (or (position #\space a) -1) )
> (cond ((= pos -1) (list a))
> ((> pos -1) (append
> (parse (subseq a 0 pos))
> (parse (subseq a (+ pos 1) (length a)))))))
>
> Any comment is welcome!
Does this give you a hint?
[2]> (parse "something very odd")
*** - Lisp stack overflow. RESET
[3]> (trace parse)
;; Tracing function PARSE.
(PARSE)
[4]> (parse "something very odd")
1. Trace: (PARSE '"something very odd")
2. Trace: (PARSE '"something")
2. Trace: PARSE ==> ("something")
2. Trace: (PARSE '"something very odd")
3. Trace: (PARSE '"something")
3. Trace: PARSE ==> ("something")
3. Trace: (PARSE '"something very odd")
4. Trace: (PARSE '"something")
4. Trace: PARSE ==> ("something")
4. Trace: (PARSE '"something very odd")
5. Trace: (PARSE '"something")
5. Trace: PARSE ==> ("something")
5. Trace: (PARSE '"something very odd")
...
If not yet, try this:
[8]> (defun parse(a)
(setq pos (or (position #\space a) -1) )
(cond ((= pos -1) (list a))
((> pos -1) (append
(parse (subseq a 0 (print pos)))
(parse (subseq a (+ (print pos) 1) (length a)))))))
;; ^^^^^^
WARNING: DEFUN/DEFMACRO: redefining PARSE; it was traced!
PARSE
[9]> (trace parse)
;; Tracing function PARSE.
(PARSE)
[10]> (parse "something very odd")
1. Trace: (PARSE '"something very odd")
9
2. Trace: (PARSE '"something")
2. Trace: PARSE ==> ("something")
-1
2. Trace: (PARSE '"something very odd")
9
3. Trace: (PARSE '"something")
3. Trace: PARSE ==> ("something")
-1
3. Trace: (PARSE '"something very odd")
9
4. Trace: (PARSE '"something")
4. Trace: PARSE ==> ("something")
-1
4. Trace: (PARSE '"something very odd")
9
5. Trace: (PARSE '"something")
5. Trace: PARSE ==> ("something")
-1
5. Trace: (PARSE '"something very odd")
9
6. Trace: (PARSE '"something")
6. Trace: PARSE ==> ("something")
-1
6. Trace: (PARSE '"something very odd")
9
7. Trace: (PARSE '"something")
7. Trace: PARSE ==> ("something")
-1
7. Trace: (PARSE '"something very odd")
9
You are modifying a global variable pos, so its value changes between
the two recursive calls to parse.
Use a local variable! Use LET
--
__Pascal Bourguignon__ http://www.informatimago.com/
Our enemies are innovative and resourceful, and so are we. They never
stop thinking about new ways to harm our country and our people, and
neither do we. -- Georges W. Bush
From: Yossarian
Subject: Re: Newbie lisp problem: string to list of strings separated by space
Date:
Message-ID: <e0ggcv$v4m$1@gaudi2.UGent.be>
Pascal Bourguignon wrote:
> Yossarian <·········@aixioma.net> writes:
>
>
>>Hi,
>>
>>I am trying to write a very simple function that accepts a string as
>>input, and that returns a list of strings as output, having a seperate
>>list item for every substring without a space.
>>
>>Example:
>>input = "something very odd"
>>output = ("something" "very" "odd")
>>
>>I tried to do this with the following function, but I can't understand
>>why it is not working.
>>
>>(defun parse(a)
>> (setq pos (or (position #\space a) -1) )
>> (cond ((= pos -1) (list a))
>> ((> pos -1) (append
>> (parse (subseq a 0 pos))
>> (parse (subseq a (+ pos 1) (length a)))))))
>>
>>Any comment is welcome!
>
>
> Does this give you a hint?
>
> [2]> (parse "something very odd")
>
> *** - Lisp stack overflow. RESET
> [3]> (trace parse)
> ;; Tracing function PARSE.
> (PARSE)
> [4]> (parse "something very odd")
> 1. Trace: (PARSE '"something very odd")
> 2. Trace: (PARSE '"something")
> 2. Trace: PARSE ==> ("something")
> 2. Trace: (PARSE '"something very odd")
> 3. Trace: (PARSE '"something")
> 3. Trace: PARSE ==> ("something")
> 3. Trace: (PARSE '"something very odd")
> 4. Trace: (PARSE '"something")
> 4. Trace: PARSE ==> ("something")
> 4. Trace: (PARSE '"something very odd")
> 5. Trace: (PARSE '"something")
> 5. Trace: PARSE ==> ("something")
> 5. Trace: (PARSE '"something very odd")
> ...
>
> If not yet, try this:
>
> [8]> (defun parse(a)
> (setq pos (or (position #\space a) -1) )
> (cond ((= pos -1) (list a))
> ((> pos -1) (append
> (parse (subseq a 0 (print pos)))
> (parse (subseq a (+ (print pos) 1) (length a)))))))
> ;; ^^^^^^
>
> WARNING: DEFUN/DEFMACRO: redefining PARSE; it was traced!
> PARSE
> [9]> (trace parse)
> ;; Tracing function PARSE.
> (PARSE)
> [10]> (parse "something very odd")
> 1. Trace: (PARSE '"something very odd")
> 9
> 2. Trace: (PARSE '"something")
> 2. Trace: PARSE ==> ("something")
> -1
> 2. Trace: (PARSE '"something very odd")
> 9
> 3. Trace: (PARSE '"something")
> 3. Trace: PARSE ==> ("something")
> -1
> 3. Trace: (PARSE '"something very odd")
> 9
> 4. Trace: (PARSE '"something")
> 4. Trace: PARSE ==> ("something")
> -1
> 4. Trace: (PARSE '"something very odd")
> 9
> 5. Trace: (PARSE '"something")
> 5. Trace: PARSE ==> ("something")
> -1
> 5. Trace: (PARSE '"something very odd")
> 9
> 6. Trace: (PARSE '"something")
> 6. Trace: PARSE ==> ("something")
> -1
> 6. Trace: (PARSE '"something very odd")
> 9
> 7. Trace: (PARSE '"something")
> 7. Trace: PARSE ==> ("something")
> -1
> 7. Trace: (PARSE '"something very odd")
> 9
>
>
> You are modifying a global variable pos, so its value changes between
> the two recursive calls to parse.
>
> Use a local variable! Use LET
Indeed, the idea was to use a local variable ...
Now, if I replace "setq" with "let", then I receive the following error.
Are there extra requirements for using "let"? What is wrong now?
(defun parse(a)
(let pos (or (position #\space a) -1) )
(cond ((= pos -1) (list a))
((> pos -1) (append
(parse (subseq a 0 pos))
(parse (subseq a (+ pos 1) (length
a)))))))
;;; Warning: Function not defined: PARSE
;;; An error occurred in function #< COMPILED-FUNCTION: #xD0F828 >:
;;; Error: The variable A is unbound
Yossarian <·········@aixioma.net> writes:
>> Use a local variable! Use LET
>
> Indeed, the idea was to use a local variable ...
> Now, if I replace "setq" with "let", then I receive the following error.
> Are there extra requirements for using "let"? What is wrong now?
>
> (defun parse(a)
> (let pos (or (position #\space a) -1) )
> (cond ((= pos -1) (list a))
> ((> pos -1) (append
> (parse (subseq a 0 pos))
> (parse (subseq a (+ pos 1) (length
> a)))))))
> ;;; Warning: Function not defined: PARSE
> ;;; An error occurred in function #< COMPILED-FUNCTION: #xD0F828 >:
> ;;; Error: The variable A is unbound
It might be a good idea to read some tutorial and some reference
manual. You wouldn't want to be taken for a Mondoshawan, would you?
Zorg: I hate warriors, too narrow-minded. I'll tell you what I do
like: a killer, a died-in-the-wood killer. Cold blooded
methodical. Now a real killer when he picked up the ZF-1,
would have immediately asked about the little red button on
the bottom of the gun.
Aknot: [Scene shifts to Aknot, who is staring in confusion at the
little red button. He shrugs and pushes it]
Zorg: [Casually smokes a cigarette as the room with the Mangalores
blows up] Bring me the priest.
http://www.imdb.com/title/tt0119116/quotes
http://www.cliki.net/Education
http://www.lispworks.com/documentation/HyperSpec/Front/Contents.htm
http://www.lispworks.com/documentation/HyperSpec/Body/s_let_l.htm
--
__Pascal Bourguignon__ http://www.informatimago.com/
CAUTION: The mass of this product contains the energy equivalent of
85 million tons of TNT per net ounce of weight.
On 2006-03-30 10:48:28 -0500, Pascal Bourguignon
<······@informatimago.com> said:
> Zorg: I hate warriors, too narrow-minded. I'll tell you what I do
> like: a killer, a died-in-the-wood killer.
^^^^^^
should be "dyed-in-the-wool"
The idiom comes from the fact that woolen garments can be dyed before
spinning, weaving or knitting or they can be dyed afterwards. Those
dyed beforehand (dyed-in-the-wool) have their color since they were
wool, even before they became yarn or a piece of cloth. Woolen items
dyed this way had much longer lasting color.
When speaking of people by analogy, a dyed-in-the-wool x has been an x
metaphorically since birth and much more strongly so than others who
came to x later in life.
see: <http://www.answers.com/topic/dyed-in-the-wool> or
<http://www.factoidcentral.com/phrases/D_files/D_46.html>
BTW, I love Gary Oldman as Zorg ;^)
Raffael Cavallaro <················@pas-d'espam-s'il-vous-plait-mac.com> writes:
> On 2006-03-30 10:48:28 -0500, Pascal Bourguignon
> <······@informatimago.com> said:
>
>> Zorg: I hate warriors, too narrow-minded. I'll tell you what I do
>> like: a killer, a died-in-the-wood killer.
> ^^^^^^
> should be "dyed-in-the-wool"
>
> The idiom comes from the fact that woolen garments can be dyed before
> spinning, weaving or knitting or they can be dyed afterwards. Those
> dyed beforehand (dyed-in-the-wool) have their color since they were
> wool, even before they became yarn or a piece of cloth. Woolen items
> dyed this way had much longer lasting color.
>
> When speaking of people by analogy, a dyed-in-the-wool x has been an x
> metaphorically since birth and much more strongly so than others who
> came to x later in life.
>
> see: <http://www.answers.com/topic/dyed-in-the-wool> or
> <http://www.factoidcentral.com/phrases/D_files/D_46.html>
Ok, I corrected the IMDb quote.
> BTW, I love Gary Oldman as Zorg ;^)
--
__Pascal Bourguignon__ http://www.informatimago.com/
THIS IS A 100% MATTER PRODUCT: In the unlikely event that this
merchandise should contact antimatter in any form, a catastrophic
explosion will result.
From: Rob Warnock
Subject: Re: Newbie lisp problem: string to list of strings separated by space
Date:
Message-ID: <ifednemd-uP3MbHZRVn-sw@speakeasy.net>
Raffael Cavallaro <················@pas-d'espam-s'il-vous-plait-mac.com> wrote:
+---------------
| Pascal Bourguignon <······@informatimago.com> said:
|
| > Zorg: I hate warriors, too narrow-minded. I'll tell you what I do
| > like: a killer, a died-in-the-wood killer.
| ^^^^^^
| should be "dyed-in-the-wool"
+---------------
Hmmm... Is this a new eggcorn? I don't see it in the database:
http://eggcorns.lascribe.net/
-Rob
-----
Rob Warnock <····@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607
Yossarian <·········@aixioma.net> writes:
>> Use a local variable! Use LET
>
> Indeed, the idea was to use a local variable ...
> Now, if I replace "setq" with "let", then I receive the following error.
> Are there extra requirements for using "let"? What is wrong now?
>
> (defun parse(a)
> (let pos (or (position #\space a) -1) )
> (cond ((= pos -1) (list a))
> ((> pos -1) (append
> (parse (subseq a 0 pos))
> (parse (subseq a (+ pos 1) (length
> a)))))))
> ;;; Warning: Function not defined: PARSE
> ;;; An error occurred in function #< COMPILED-FUNCTION: #xD0F828 >:
> ;;; Error: The variable A is unbound
It might be a good idea to read some tutorial and some reference
manual. You wouldn't want to be taken for a Mangalore, would you?
Zorg: I hate warriors, too narrow-minded. I'll tell you what I do
like: a killer, a died-in-the-wood killer. Cold blooded
methodical. Now a real killer when he picked up the ZF-1,
would have immediately asked about the little red button on
the bottom of the gun.
Aknot: [Scene shifts to Aknot, who is staring in confusion at the
little red button. He shrugs and pushes it]
Zorg: [Casually smokes a cigarette as the room with the Mangalores
blows up] Bring me the priest.
http://www.imdb.com/title/tt0119116/quotes
http://www.cliki.net/Education
http://www.lispworks.com/documentation/HyperSpec/Front/Contents.htm
http://www.lispworks.com/documentation/HyperSpec/Body/s_let_l.htm
--
__Pascal Bourguignon__ http://www.informatimago.com/
CAUTION: The mass of this product contains the energy equivalent of
85 million tons of TNT per net ounce of weight.
From: Dmitry Gorbatovsky
Subject: Re: Newbie lisp problem: string to list of strings separated by space
Date:
Message-ID: <e0hdpb$pm6$1@emma.aioe.org>
Yossarian wrote:
> Hi,
>
> I am trying to write a very simple function that accepts a string as
> input, and that returns a list of strings as output, having a seperate
> list item for every substring without a space.
>
> Example:
> input = "something very odd"
> output = ("something" "very" "odd")
>
> I tried to do this with the following function, but I can't understand
> why it is not working.
>
> (defun parse(a)
> (setq pos (or (position #\space a) -1) )
> (cond ((= pos -1) (list a))
> ((> pos -1) (append
> (parse (subseq a 0 pos))
> (parse (subseq a (+ pos 1) (length a)))))))
>
> Any comment is welcome!
>
> Regards,
>
> Wouter
Or maybe like that:
(defun split-by-one-space (string)
"Returns a list of substrings of string
divided by ONE space each.
Note: Two consecutive spaces will be seen as if there were an empty string
between them."
(loop for i = 0 then (1+ j)
as j = (position #\Space string :start i)
collect (subseq string i j)
while j))
From cl-cookbook...
Cheers
--
*It is easy to lie with statistics, but it's a lot easier to lie without
them.
Yossarian <·········@aixioma.net> writes:
> Hi,
>
> I am trying to write a very simple function that accepts a string as
> input, and that returns a list of strings as output, having a seperate
> list item for every substring without a space.
>
> Example:
> input = "something very odd"
> output = ("something" "very" "odd")
>
> I tried to do this with the following function, but I can't understand
> why it is not working.
>
> (defun parse(a)
> (setq pos (or (position #\space a) -1) )
> (cond ((= pos -1) (list a))
> ((> pos -1) (append
> (parse (subseq a 0 pos))
> (parse (subseq a (+ pos 1) (length a)))))))
>
> Any comment is welcome!
Your design is basically correct but inefficient.
First you need to make pos a local variable
(let ((pos ..... some number of closing parens
(cond ....
^
|
`---- notice the indentation
Your editor will indent your code for you. In emacs its
ctrl-alt-h to set the region to the enclosing defun and
crtl-alt-\ to adjust the indentation.
If this makes it line up
(let ((pos ...
(cond
you have one too many closing parentheses on the previous line
The other way to check is to position the cursor at the end
of the init forms
Position cursor here
|
|
V
(let ((pos ....))
^ ^
| |
These two get highlighted as the matching parentheses
In emacs you enable this with meta-x show-paren-mode
Next point is that the position function is carefully
designed to return either the position or Common Lisp's
false value, NIL, with the intention that the value is
directly usable as a boolean. Maybe I should say that the
other way round, Common Lisp's if operator is carefully
designed so that all numbers, including 0, count as
true. Thus the value returned by position is directly usable
as a boolean
(let ((pos ...))
(if pos
(code for when position is a number)
(code for when position is false)))
(append
(parse (subseq a 0 pos))
(parse (subseq a (+ pos 1) (length a))))
This could be
(cons
(subseq a 0 pos)
(parse (...as before...)))
Position finds the first matching item, so there is no need
to re-parse the leading subsequence.
The end argument to subseq is optional. You could just say
(subseq a (+ pos 1))
and that would also copy all the way to the end.
This brings up the efficiency issue. If there are many
separators the code copies the remaining characters many
times, so the run time is quadratic in the length of the
string when it ought to be linear.
The simplest solution is to add a numerical start argument
to parse, and use the :start key-word for position.
New programming languages often have annoying gaps.
Common Lisp was a unification effort, intended to unify
various previous dialects of Lisp. The upside is that Common
Lisp was an "old" language even when it was "new". The gaps
had all been discovered by programmers working on previous
dialects and Common Lisp ensured that they were all filled.
The ????-side is that it is a big language that combines
lots of useful features. Look at the examples that have been
posted using the LOOP macro.
That presents a problem to the autodidact. If you just
plunge in you are likely to spread yourself too thinly over
many different features and become frustrated. It is
probably best to follow a systematic tutorial. Graham's ANSI
Common Lisp is highly regarded as fast paced tutorial for
those already familiar with programming. (It is the book I
read to learn Common Lisp) It will be interesting to see if
Peter Seibel's impressive Practical Common Lisp
http://www.gigamonkeys.com/book/functions.html
suplants it.
Alan Crowe
Edinburgh
Scotland
From: Yossarian
Subject: Re: Newbie lisp problem: string to list of strings separated by space
Date:
Message-ID: <e0jelj$1b4$1@gaudi2.UGent.be>
Alan Crowe wrote:
> Yossarian <·········@aixioma.net> writes:
>
>
>>Hi,
>>
>>I am trying to write a very simple function that accepts a string as
>>input, and that returns a list of strings as output, having a seperate
>>list item for every substring without a space.
>>
>>Example:
>>input = "something very odd"
>>output = ("something" "very" "odd")
>>
>>I tried to do this with the following function, but I can't understand
>>why it is not working.
>>
>>(defun parse(a)
>> (setq pos (or (position #\space a) -1) )
>> (cond ((= pos -1) (list a))
>> ((> pos -1) (append
>> (parse (subseq a 0 pos))
>> (parse (subseq a (+ pos 1) (length a)))))))
>>
>>Any comment is welcome!
>
>
> Your design is basically correct but inefficient.
>
> First you need to make pos a local variable
>
> (let ((pos ..... some number of closing parens
> (cond ....
> ^
> |
> `---- notice the indentation
>
> Your editor will indent your code for you. In emacs its
> ctrl-alt-h to set the region to the enclosing defun and
> crtl-alt-\ to adjust the indentation.
>
> If this makes it line up
>
> (let ((pos ...
> (cond
>
> you have one too many closing parentheses on the previous line
>
> The other way to check is to position the cursor at the end
> of the init forms
>
> Position cursor here
> |
> |
> V
> (let ((pos ....))
> ^ ^
> | |
> These two get highlighted as the matching parentheses
>
> In emacs you enable this with meta-x show-paren-mode
>
> Next point is that the position function is carefully
> designed to return either the position or Common Lisp's
> false value, NIL, with the intention that the value is
> directly usable as a boolean. Maybe I should say that the
> other way round, Common Lisp's if operator is carefully
> designed so that all numbers, including 0, count as
> true. Thus the value returned by position is directly usable
> as a boolean
>
> (let ((pos ...))
> (if pos
> (code for when position is a number)
> (code for when position is false)))
>
> (append
> (parse (subseq a 0 pos))
> (parse (subseq a (+ pos 1) (length a))))
>
> This could be
>
> (cons
> (subseq a 0 pos)
> (parse (...as before...)))
>
> Position finds the first matching item, so there is no need
> to re-parse the leading subsequence.
>
> The end argument to subseq is optional. You could just say
>
> (subseq a (+ pos 1))
>
> and that would also copy all the way to the end.
>
> This brings up the efficiency issue. If there are many
> separators the code copies the remaining characters many
> times, so the run time is quadratic in the length of the
> string when it ought to be linear.
>
> The simplest solution is to add a numerical start argument
> to parse, and use the :start key-word for position.
>
> New programming languages often have annoying gaps.
> Common Lisp was a unification effort, intended to unify
> various previous dialects of Lisp. The upside is that Common
> Lisp was an "old" language even when it was "new". The gaps
> had all been discovered by programmers working on previous
> dialects and Common Lisp ensured that they were all filled.
> The ????-side is that it is a big language that combines
> lots of useful features. Look at the examples that have been
> posted using the LOOP macro.
>
> That presents a problem to the autodidact. If you just
> plunge in you are likely to spread yourself too thinly over
> many different features and become frustrated. It is
> probably best to follow a systematic tutorial. Graham's ANSI
> Common Lisp is highly regarded as fast paced tutorial for
> those already familiar with programming. (It is the book I
> read to learn Common Lisp) It will be interesting to see if
> Peter Seibel's impressive Practical Common Lisp
>
> http://www.gigamonkeys.com/book/functions.html
>
> suplants it.
>
> Alan Crowe
> Edinburgh
> Scotland
Thanks a lot! That's what I call a valuable answer! ... think you
showed some essential properties of functional programming, and Common
Lisp in particular. I didn't realize that indentation could be that
important.
I indeed plan to read Graham's book, which seems to be "the" common lisp
book. I used Haskell some years ago, and was to optimistic in the idea
that it wouldn't take that much time to do some elementary stuff in
lisp. I know better now ...
regards,
wouter