Help required: Is there a way to split up one element into several?

5 views
Skip to first unread message

Erik Halvarsson

unread,
Mar 30, 2000, 3:00:00 AM3/30/00
to
I am coding some stuff in AutoLISP, AutoCAD R14.
From an external file I need to get some data, and it's stored like:

VKA100 707898.512 78172.497 143.803

a simple xyz coordinate. When I use the (readline file) function, that
string becomes one single element in the list I assign it to. What I
need is four different elements in the list but I have so far no clue
how to achive this. Would be great if anyone out there could help me.

Erik Halvarsson
ericth...@hotmail.com

Jonathan BAILLEUL

unread,
Mar 30, 2000, 3:00:00 AM3/30/00
to

Unfortunately, I have the same problem now.
At the current time, I reused the "tokens" function from Paul Graham's
"Ansi Common Lisp", giving as parameter a very simple lambda: this
builds up a string tokenizer, ie a function returning a list of
substrings (in your case: '("VKA100" "707898.512" "78172.497" "143.803")
).
See the sample code below.

The problem I have now is:
How to convert "707898.512" to a single-float number? I'm really stuck
and very frustrated because I think this is a newbie question.


>>>>>>>>>>
The promised sample code:

;;ACL
(defun tokens (str test start)
(let ((p1 (position-if test str :start start)))
(if p1
(let ((p2 (position-if #'(lambda (c)
(not (funcall test c)))
str :start p1)))
(cons (subseq str p1 p2)
(if p2
(tokens str test p2)
nil)))
nil)))


(defun tokenize (str)
"returns a list of tokens, ie #\SPACE-separated elements"
(let ((nospc (lambda (x) (not (eq #\SPACE x)))))
(tokens str nospc 0)))


(defun fetch-arg-value (arg str)
"returns the token just after the given element in the string"
(let ((arglen (length arg))
(argpos (search arg str)))
(progn (assert argpos)
(car (tokenize (subseq str (+ arglen
argpos)))))))

--
----------------------------------------------
Jonathan BAILLEUL (bail...@emi.u-bordeaux.fr)
Maitrise Informatique, Universite Bordeaux I

William Deakin

unread,
Mar 30, 2000, 3:00:00 AM3/30/00
to
Jonathan BAILLEUL wrote:

> How to convert "707898.512" to a single-float number? I'm really stuck
> and very frustrated because I think this is a newbie question.

In the recent(ish) past there has been some debate about string to number
conversion. Due to my goldfish-esque memory I cannot remember the outcome.
All I can remember is that this is not as straightforward as you might first
think :(

My advice would be to try having a dig on deja.com. I tried but I'm having
problems connecting to the 'net at the moment :(

Best Regards,

:) will


Raymond Wiker

unread,
Mar 30, 2000, 3:00:00 AM3/30/00
to
William Deakin <wi...@pindar.com> writes:

> Jonathan BAILLEUL wrote:
>
> > How to convert "707898.512" to a single-float number? I'm really stuck
> > and very frustrated because I think this is a newbie question.
>
> In the recent(ish) past there has been some debate about string to number
> conversion. Due to my goldfish-esque memory I cannot remember the outcome.
> All I can remember is that this is not as straightforward as you might first
> think :(

read-from-string or coerce, perhaps? If you use
read-from-string, you could use the second return value to check that
the entire contents of the string was read, along with a check that
the value read is actually a signle-float. Note that you may want to
bind *read-default-float-format* around the call to read-from-string.

--
Raymond Wiker, Orion Systems AS
+47 370 61150

Francis Leboutte

unread,
Mar 30, 2000, 3:00:00 AM3/30/00
to
Jonathan BAILLEUL <bail...@emi.u-bordeaux.fr> wrote:

>The problem I have now is:

>How to convert "707898.512" to a single-float number? I'm really stuck
>and very frustrated because I think this is a newbie question.
>

Vous pourriez utiliser ceci :

(declaim (inline whitespace-p))
(defun whitespace-p (char)
(declare (OPTIMIZE (speed 3) (safety 1)))
(char= char #\space))
(declaim (notinline whitespace-p))

(defun parse-float (string start end)
"Based on parse-float from CMU Lisp repository, by Mark Kantrowitz.
If there's nothing in the string but whitespace return 0. Return 0
too, if there
is nothing but whitespaces and one dot (or a +, a -, a e). End may be
NIL
(meaning end of the string)"
(declare (OPTIMIZE (speed 3) (safety 1)))
(declare (INLINE whitespace-p))
(setq end (or end (length string)))
;; Skip over whitespace. If there's nothing but whitespace return 0
(let ((index (or (position-if-not #'whitespace-p string
:start start :end end)
(return-from parse-float (values 0.0 end))))
(minusp nil) (decimalp nil) (found-digit nil)
(before-decimal 0) (after-decimal 0) (decimal-counter 0)
(exponent 0)
(result 0)
(radix 10))
(declare (fixnum index))
;; Take care of optional sign.
(let ((char (char string index)))
(cond ((char= char #\-)
(setq minusp t)
(incf index))
((char= char #\+)
(incf index))))
(loop
until (= index end)
for char = (char string index)
as weight = (digit-char-p char radix)
do
(cond ((and weight (not decimalp))
;; A digit before the decimal point
(setq before-decimal (+ weight (* before-decimal radix))
found-digit t))
((and weight decimalp)
;; A digit after the decimal point
(setq after-decimal (+ weight (* after-decimal radix))
found-digit t)
(incf decimal-counter))
((and (char= char #\.) (not decimalp))
;; The decimal point
(setq decimalp t))
((and (or (char-equal char #\E)
(char-equal char #\D)
(char-equal char #\F)
(char-equal char #\S)
(char-equal char #\L))
(= radix 10))
(multiple-value-bind (num idx)
(parse-integer string :start (1+ index) :end end
:radix radix :junk-allowed NIL)
(setq exponent (or num 0)
index idx)
(when (= index end) (return nil))))
((whitespace-p char)
(when (position-if-not #'whitespace-p string
:start (1+ index) :end end)
(error "There's junk in this string: ~S." string))
(return nil))
(t
(error "There's junk in this string: ~S." string)))
(incf index))
;; Cobble up the resulting number
(setq result (coerce (* (+ before-decimal
(* after-decimal
(coerce (expt radix (-
decimal-counter))
'float)))
(coerce (expt radix exponent)
'float))
'float))
;; Return the result
(values
(if found-digit
(if minusp (- result) result)
0.0)
index)))

--
Francis Leboutte
f...@algo.be www.algo.be +32-(0)4.388.39.19

Alex Henderson

unread,
Mar 30, 2000, 3:00:00 AM3/30/00
to
> I am coding some stuff in AutoLISP, AutoCAD R14.
> From an external file I need to get some data, and it's stored like:
>
> VKA100 707898.512 78172.497 143.803

(defmacro collect (term-cond form &key count)
`(do ((result-list nil)
(last-cons nil (if last-cons
(cdr last-cons)
result-list))
. ,(when count '((i 0 (1+ i)))))
(,(if count `(or (>= i ,count)
,term-cond)
term-cond)
result-list)
(if result-list
(setf (cdr last-cons) (list ,form))
(setf result-list (list ,form)))))

(defun parse-file (path)
(with-open-file (stream path)
(collect (not (listen stream))
(collect (not (listen stream))
(let ((val (read stream)))
(if (numberp val)
(coerce val 'float)
val))
:count 4))))

This is presuming that each line contains 4 elements, and coerces every
number to a float.

A

--
Real programmers don't document. If it was hard
to write, it should be hard to understand.

William Deakin

unread,
Mar 30, 2000, 3:00:00 AM3/30/00
to
Raymond Wiker wrote:

> read-from-string or coerce, perhaps?

Yes that'll do nicely, thank you.

[My net link is back up and I have had a chance to check up on deja. What I was
thinking of was the parse-number/parse-float debate last year]

Best Regards,

:) will

Alex Henderson

unread,
Mar 30, 2000, 3:00:00 AM3/30/00
to
> (defmacro collect (term-cond form &key count)
> `(do ((result-list nil)
> (last-cons nil (if last-cons
> (cdr last-cons)
> result-list))
> . ,(when count '((i 0 (1+ i)))))
> (,(if count `(or (>= i ,count)
> ,term-cond)
> term-cond)
> result-list)
> (if result-list
> (setf (cdr last-cons) (list ,form))
> (setf result-list (list ,form)))))

Apologies, please take this hideous macro instead to read:

(defmacro collect (term-cond form &key count)

(let ((result-list (gensym))
(last-cons (gensym)))
`(do ((,result-list nil)
(,last-cons nil (if ,last-cons
(cdr ,last-cons)
,result-list))


. ,(when count '((i 0 (1+ i)))))
(,(if count `(or (>= i ,count)
,term-cond)
term-cond)

,result-list)
(if ,result-list
(setf (cdr ,last-cons) (list ,form))
(setf ,result-list (list ,form))))))

A

--
A successful man is one who makes more money than his wife can spend.
A successful woman is one who can find such a man.

Pierre R. Mai

unread,
Mar 30, 2000, 3:00:00 AM3/30/00
to
Raymond Wiker <ray...@orion.no> writes:

> William Deakin <wi...@pindar.com> writes:
>
> > Jonathan BAILLEUL wrote:
> >

> > > How to convert "707898.512" to a single-float number? I'm really stuck
> > > and very frustrated because I think this is a newbie question.
> >

> > In the recent(ish) past there has been some debate about string to number
> > conversion. Due to my goldfish-esque memory I cannot remember the outcome.
> > All I can remember is that this is not as straightforward as you might first
> > think :(
>
> read-from-string or coerce, perhaps? If you use
> read-from-string, you could use the second return value to check that
> the entire contents of the string was read, along with a check that
> the value read is actually a signle-float. Note that you may want to
> bind *read-default-float-format* around the call to read-from-string.

Depending on how trustworthy and errorfree the source of the string
is, you might want to either do a pre-check on the string, ensuring
that it only consists of numerals and points, or make the reader safe,
by binding *read-eval* to nil, and using a readtable that will signal
errors on all non-legal characters.

Regs, Pierre.

--
Pierre Mai <pm...@acm.org> PGP and GPG keys at your nearest Keyserver
"One smaller motivation which, in part, stems from altruism is Microsoft-
bashing." [Microsoft memo, see http://www.opensource.org/halloween1.html]

Erik Naggum

unread,
Mar 30, 2000, 3:00:00 AM3/30/00
to
* Erik Halvarsson <ericth...@hotmail.com>

| From an external file I need to get some data, and it's stored like:
|
| VKA100 707898.512 78172.497 143.803
|
| a simple xyz coordinate. When I use the (readline file) function, that
| string becomes one single element in the list I assign it to. What I
| need is four different elements in the list but I have so far no clue
| how to achive this. Would be great if anyone out there could help me.

if each line is known to consist of these four elements, the first looks
very much a symbol, and programmer time is more important than much
anything else, just use the function read. here's a quick shot at it:

(let ((*package* (make-package (gensym) :use ())))
(unwind-protect
(loop for line = (loop with first = (read <stream> nil)
if (not first)
then do (loop-finish)
else collect (symbol-name first)
repeat 3
collect (read <stream>))
while line
collect line)
(delete-package *package*)))

#:Erik

Andrew K. Wolven

unread,
Mar 30, 2000, 3:00:00 AM3/30/00
to
You guys:
AutoLisp is not Common Lisp.

you might as well be giving him scheme answers.
(I don't think packages, macros, lexical binding or any of that exist in
AutoCAD 14)

Mr. Halvarsson:
try putting the word 'AutoLisp' in the subject.
Perhaps Reini Urban will answer.
He's the big AutoLisp hacker on this list.

AKW

Erik Naggum

unread,
Mar 31, 2000, 3:00:00 AM3/31/00
to
* "Andrew K. Wolven" <awo...@redfernlane.org>

| AutoLisp is not Common Lisp.

well, comp.lang.lisp is not an AutoLisp newsgroup.
comp.cad.autocad might be a good place to start.

#:Erik

Andrew K. Wolven

unread,
Mar 31, 2000, 3:00:00 AM3/31/00
to

Erik Naggum wrote:

I wonder how many autolisp to common lisp converts there are.
Certainly, I can't be the only one.

Answer me three questions, Erik:

Why is Franz in berkeley?
Why do people look like their pets?
(last question omitted)

-AKW


Christophe Rhodes

unread,
Mar 31, 2000, 3:00:00 AM3/31/00
to
Erik Halvarsson <ericth...@hotmail.com> writes:

> [snip AutoLISP help request]

> From an external file I need to get some data, and it's stored like:
>
> VKA100 707898.512 78172.497 143.803
>

I'm afraid I'm not going to be helpful in this specific
endeavour. Sorry.

However, the parse-number thread from last summer got me to thinking,
and since I should actually be doing work for my finals, I got a bit
bored and started implementing[1] one of the cutest ideas I've seen:

* (setf x (make-list 4))

(NIL NIL NIL NIL)
* (setf (format nil "~s ~f ~f ~f" (first x) (second x) (third x) (fourth x))

"VKA100 707898.512 78172.497 143.803")

"VKA100 707898.512 78172.497 143.803"
* x

(VKA100 707898.5 78172.5 143.803)

;-)

My code is, needless to say, incomplete in the extreme. I have got
working:
~b, ~d, ~f, ~o, ~x with no parameters,
~r with one parameter,
~@c and ~c,
~s, and
~@{ ~}

Obviously, there's much more to do, and much to think about, but it is
quite fun...[2]

* (setf (format nil "~@{~31r ~}" x y z w) "JUST ANOTHER LISP HACKER ")

"JUST ANOTHER LISP HACKER "
* (list x y z w)

(595756 9556552524 643802 496307950)

;-)

Christophe

[1] Let's face it, it's probably not going to get finished...

[2] Offers to laugh at my code gratefully accepted -- this is
definitely part of the learning process...
--
(macrolet ((f (a b) `(unless (equal ,a "") (princ (aref ,a 0)) (setf ,a
(subseq ,a 1)) (,b))) (z (&rest a) `(format nil "~@{~35r~^ ~}" ,@a))) (
let ((w (z 693 29204 28104384)) (x (z 1984050605838 12977))) (labels ((
y () (f w z))(z () (f x y))) (y) (terpri))))#|Jesus College,Cambridge|#

Paolo Amoroso

unread,
Apr 2, 2000, 4:00:00 AM4/2/00
to
On 30 Mar 2000 15:06:45 +0000, Erik Naggum <er...@naggum.no> wrote:

(let ((*package* (make-package (gensym) :use ())))
(unwind-protect
(loop for line = (loop with first = (read <stream> nil)
if (not first)
then do (loop-finish)
else collect (symbol-name first)
repeat 3
collect (read <stream>))
while line
collect line)
(delete-package *package*)))

What is the purpose of the temporary package, i.e. the one which is bound
to *PACKAGE*? To avoid cluttering a useful package with symbols that are
interned just to get their names?


Paolo
--
EncyCMUCLopedia * Extensive collection of CMU Common Lisp documentation
http://cvs2.cons.org:8000/cmucl/doc/EncyCMUCLopedia/

Erik Naggum

unread,
Apr 2, 2000, 4:00:00 AM4/2/00
to
* Paolo Amoroso <amo...@mclink.it>

| What is the purpose of the temporary package, i.e. the one which is bound
| to *PACKAGE*? To avoid cluttering a useful package with symbols that are
| interned just to get their names?

yes, that is precisely the reason I chose to set up a temporary package.

#:Erik

Reply all
Reply to author
Forward
0 new messages