From: Erik Halvarsson
Subject: Help required: Is there a way to split up one element into several?
Date: 
Message-ID: <38E32079.69886751@hotmail.com>
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
············@hotmail.com

From: Jonathan BAILLEUL
Subject: Re: Help required: Is there a way to split up one element into several?
Date: 
Message-ID: <38E32AF1.723B1798@emi.u-bordeaux.fr>
Erik Halvarsson wrote:
> 
> 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
> ············@hotmail.com

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 (········@emi.u-bordeaux.fr)
Maitrise Informatique, Universite Bordeaux I
From: William Deakin
Subject: Re: Help required: Is there a way to split up one element into several?
Date: 
Message-ID: <38E3311A.1F445EE0@pindar.com>
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
From: Raymond Wiker
Subject: Re: Help required: Is there a way to split up one element into several?
Date: 
Message-ID: <87ya70n2cf.fsf@foobar.orion.no>
William Deakin <·····@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
From: William Deakin
Subject: Re: Help required: Is there a way to split up one element into several?
Date: 
Message-ID: <38E34F71.E6623B6A@pindar.com>
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
From: Pierre R. Mai
Subject: Re: Help required: Is there a way to split up one element into several?
Date: 
Message-ID: <87aejgsfgl.fsf@orion.dent.isdn.cs.tu-berlin.de>
Raymond Wiker <·······@orion.no> writes:

> William Deakin <·····@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 <····@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]
From: Francis Leboutte
Subject: Re: Help required: Is there a way to split up one element into several?
Date: 
Message-ID: <amh6eskqh8651fhp7peaben9ad8nik66pv@4ax.com>
Jonathan BAILLEUL <········@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
··@algo.be   www.algo.be   +32-(0)4.388.39.19
From: Alex Henderson
Subject: Re: Help required: Is there a way to split up one element into several?
Date: 
Message-ID: <38E34C01.4511A04D@hermes.cam.ac.uk>
> 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.
From: Alex Henderson
Subject: Re: Help required: Is there a way to split up one element into several?
Date: 
Message-ID: <38E34F4C.4FA4C88F@hermes.cam.ac.uk>
> (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.
From: Erik Naggum
Subject: Re: Help required: Is there a way to split up one element into several?
Date: 
Message-ID: <3163417605117716@naggum.no>
* Erik Halvarsson <············@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
From: Andrew K. Wolven
Subject: Re: Help required: Is there a way to split up one element into several?
Date: 
Message-ID: <38E3EAD7.9372D612@redfernlane.org>
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 wrote:

> * Erik Halvarsson <············@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
From: Erik Naggum
Subject: Re: Help required: Is there a way to split up one element into several?
Date: 
Message-ID: <3163497050252832@naggum.no>
* "Andrew K. Wolven" <·······@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
From: Andrew K. Wolven
Subject: Re: Help required: Is there a way to split up one element into several?
Date: 
Message-ID: <38E4B8A1.53C46E7F@redfernlane.org>
Erik Naggum wrote:

> * "Andrew K. Wolven" <·······@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

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
From: Paolo Amoroso
Subject: Re: Help required: Is there a way to split up one element into several?
Date: 
Message-ID: <EvblOJctZ9Ijx3vaESfMqO+8df9u@4ax.com>
On 30 Mar 2000 15:06:45 +0000, Erik Naggum <····@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/
From: Erik Naggum
Subject: Re: Help required: Is there a way to split up one element into several?
Date: 
Message-ID: <3163690604532935@naggum.no>
* Paolo Amoroso <·······@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
From: Christophe Rhodes
Subject: Re: Help required: Is there a way to split up one element into several?
Date: 
Message-ID: <sqya6zcel5.fsf@lambda.jesus.cam.ac.uk>
Erik Halvarsson <············@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|#