TheSwamp

Code Red => AutoLISP (Vanilla / Visual) => Topic started by: Daniel J. Ellis on March 24, 2009, 09:58:50 AM

Title: How lisp tell if a string is a number?
Post by: Daniel J. Ellis on March 24, 2009, 09:58:50 AM
I'm working on updating a plot renumbering routine I wrote about a year ago.

We always put plot numbers on their own layer, so the routine originally worked by processing all of the objects on that layer.

This works OK, unless the plot number text isn't actually a number (for example, somone might want to note a binstore).

Is there a way to test whether the contents of a string are actually a number?

dJE
Title: Re: How lisp tell if a string is a number?
Post by: MP on March 24, 2009, 10:04:09 AM
Code: [Select]
(defun _DistOf ( x / result fixed )

[color=green]    ;;  Convert a string to a numerical value if possible. Also, if it
    ;;  can be determined that the intent of the string representation
    ;;  is that the number is to be an integer rather than an a real an
    ;;  integer is returned.
[/color]
    (vl-some
       '(lambda ( base ) (setq result (distof x base)))
       '(2 1 5 3 4)
    )

    (if result
        (if (vl-string-position 46 x)
            result [color=green]    ;; assume result is a real[/color]
            (if (eq result (setq fixed (fix result)))
                fixed  [color=green];; assume result is an integer[/color]
                result [color=green];; assume result is a real[/color]
            )
        )
    )
)

Code: [Select]
(if (setq dist (_DistOf (setq str "123.2")))
    (_DoStuffWithDist dist)
    (_DoStuffWithStr str)
)

Modify to suit. :)
Title: Re: How lisp tell if a string is a number?
Post by: gile on March 24, 2009, 10:04:49 AM
Hi,

(numberp (read str))
Title: Re: How lisp tell if a string is a number?
Post by: CAB on March 24, 2009, 10:14:57 AM
Funny you should ask as this was just discussed on another forum.

Like Michael's, this will return a number or nil
Code: [Select]
(defun txt2num ( txt )
  (cond
    ((distof txt 5))
    ((distof txt 2))
    ((distof txt 1))
    ((distof txt 4))
    ((distof txt 3))
  )
)

This will test for a number within a string. (not what you want)
Code: [Select]
(vl-some '(lambda (x) (< 47 x 50)) (vl-string->list "your string 2"))
I like gile's test.
Title: Re: How lisp tell if a string is a number?
Post by: MP on March 24, 2009, 10:19:41 AM
I suppose we should ask for some typical data.

For example if the candidate values are always simple ints or floats (123 | 123.4) then the _DistOf function I provided is overkill, as (numberp (read "123")) -> T or (numberp (read "123.4")) -> T.

However, if the data may have fractions etc. that need to be properly interpreted as numerical values then (_DistOf "1-1/2\"") => 1.5 would be the route to go as (numberp (read "1-1/2\"")) would return nil.

PS: Nicely done Gile. :)
Title: Re: How lisp tell if a string is a number?
Post by: MP on March 24, 2009, 10:20:16 AM
Funny you should ask as this was just discussed on another forum.

traitor :P
Title: Re: How lisp tell if a string is a number?
Post by: CAB on March 24, 2009, 10:35:48 AM
I don't view our neighbors as enemies.
So don't blow my cover as a spy. 8-)
Title: Re: How lisp tell if a string is a number?
Post by: CAB on March 24, 2009, 10:36:29 AM
This also generates an error
(numberp (read ".5   "))  
Title: Re: How lisp tell if a string is a number?
Post by: Mark on March 24, 2009, 10:38:58 AM
I suppose we should ask for some typical data.
Yep, that would help. :)
Title: Re: How lisp tell if a string is a number?
Post by: Mark on March 24, 2009, 10:39:40 AM
Code: [Select]
(numberp (read "11BN"))
nil
Title: Re: How lisp tell if a string is a number?
Post by: MP on March 24, 2009, 10:40:13 AM
I don't view our neighbors as enemies.
So don't blow my cover as a spy. 8-)

forum slut

there, I said it

:lmao:
Title: Re: How lisp tell if a string is a number?
Post by: MP on March 24, 2009, 10:41:13 AM
Code: [Select]
(numberp (read "11BN")) => nil

But ... should "11BN" be interpreted as a number? I'm not thinking so. :)
Title: Re: How lisp tell if a string is a number?
Post by: CAB on March 24, 2009, 10:45:54 AM
Hey if you like sex what better than to sleep around. ;-)
Title: Re: How lisp tell if a string is a number?
Post by: MP on March 24, 2009, 10:49:09 AM
If ya can't be good might as well be bad. :evil:
Title: Re: How lisp tell if a string is a number?
Post by: Daniel J. Ellis on March 24, 2009, 04:23:59 PM
MP, I'm sorry, that's way beyond me.  Do all possible numbers need entering into the list-I can't believe that would be the case?  If so that would rule out its use here (it would leaving me needing to create a random? list up to 1000).  I can find evidence that VL-SOME is an autolisp function,  but nothing to suggest what it might do.  What do FIXED and RESULT need to be set to?  How do distof, x, and base get generated?  I assume one of them is the test string?

CAB, I assume your use of DISTOF is the one MP created?  Similarly or seem to need to process through all possible values?

Gile, this seems to be closest to what I want.  I assume that this will work on an non-number string without crashing?  Would I use it:
<code>
(IF
    (numberp (READ txt))
    (SETQ txt2 (ATOI txt))
)
</code>

Typical data are plot numbers on an housing estate, so values are always integers, starting from 1 up to about 600.  In terms of settings I'm going up to about 1000, purely because I can't imagine a situation where a greater value would be required/encountered.  I will go on to manipulate the number (comparison, addition or subtraction)  I just want to ensure the string is indeed a number to avoid errors and crashed.

dJE
Title: Re: How lisp tell if a string is a number?
Post by: CAB on March 24, 2009, 04:44:27 PM
To solve your specific problem I would use this:
Code: [Select]
(if (and (setq num (distof str 2)) ; got a number else nil
          (setq num (fix num))      ; make an interger
          (< 0 num 1000)            ; range check
     )
   ;;  Do your plot using num var
)
Title: Re: How lisp tell if a string is a number?
Post by: VovKa on March 24, 2009, 05:16:19 PM
one more, nothing but digits allowed :)
Code: [Select]
(= str (itoa (atoi str)))
Title: Re: How lisp tell if a string is a number?
Post by: hermanm on March 24, 2009, 11:11:16 PM
Code: [Select]
;;;----------------------str2num.lsp-------------------
;;;converts a string representing a number into a real or integer
;;;----------------------------------------------------
(defun str2num (str / chlst)
  (cond
    ((member (type str) '(INT REAL)) str);is a number, so return it
    ((= (type str) 'STR)
     (progn
       (setq chlst (vl-string->list str))
       (if (member nil
                   (mapcar
                     (function (lambda (x)
                                 (and (/= x 47)
                                      (> 58 x 44)
                                 )
                               )
                     )
                     chlst
                   )
           )
         nil ; the string does not represent a number
         (if (member 46 chlst) ;contains a decimal point
           (atof str) ;real
           (atoi str) ;integer
         );if
       );if
     );progn
    )
    ((= (type str) 'SYM) (str2num (eval str)));recurse on evaluated arg
    (T nil);not a number or a string which represents a number
  )
);str2num

Title: Re: How lisp tell if a string is a number?
Post by: MP on March 24, 2009, 11:48:30 PM
MP, I'm sorry, that's way beyond me.

Sorry, trying to help, not confuse.

Do all possible numbers need entering into the list-I can't believe that would be the case?

No, I showed you how to use the function (which is supposed to make your life easier). Despite the fact that said function is overkill given the typical data being numbers as strings "starting from 1 up to about 600" as you put it, I'll try to explain for completeness' sake.

Let's say the string you wish to test is "123". If it can be converted to a number you want to use it in a calculation, say multiply it by 2, returning the result to the caller, otherwise you want to tell the user the string could not be coerced to a number and return nil to the caller.

Code: [Select]
(progn

    (setq str "123")

    (if (setq num (_DistOf str))
        (* 2 num)
        (progn (princ (strcat "String \"" str "\" cannot be coerced to a number.")) nil)
    )

)

==> 246

Now try it again but pass string "ABC".

Code: [Select]
(progn

    (setq str "ABC")

    (if (setq num (_DistOf str))
        (* 2 num)
        (progn (princ (strcat "String \"" str "\" cannot be coerced to a number.")) nil)
    )

)

==> String "ABC" cannot be coerced to a number.nil

Put one more way ... using your own example from later in the thread:

Instead of this:

Code: [Select]
(IF (numberp (READ txt))
    (SETQ txt2 (ATOI txt))
)

All you would have to do is this:

Code: [Select]
(if (setq num (_DistOf txt))
    (Do_Something_With_Num num)
)

PS: Using a variable named txt2 to represent a numerical value isn't advisable from a documentation perspective.

If so that would rule out its use here (it would leaving me needing to create a random? list up to 1000).

Sorry but you completely lost me.

I can find evidence that VL-SOME is an autolisp function,  but nothing to suggest what it might do.

It's in the AutoLISP Reference:

      Checks whether the predicate (the test) is not nil for (at least) one element combination.

In layman's terms it means the function will return true (and immediately stop processing) if one of the list items produces a non nil result when used in the test function, otherwise it will return nil.

What do FIXED and RESULT need to be set to?

"You" don't need to set them to anything, they are variables local to the _DistOf function, and are set / used by same.

How do distof, x, and base get generated?  I assume one of them is the test string?

Same as preceding comment.

HTH.
Title: Re: How lisp tell if a string is a number?
Post by: ElpanovEvgeniy on March 25, 2009, 02:52:41 AM
I have, only one variant...

Code: [Select]
(wcmatch "your string 2" "*#*")
Title: Re: How lisp tell if a string is a number?
Post by: Daniel J. Ellis on March 25, 2009, 03:28:08 AM
MP, I'm sorry, that's way beyond me.

Sorry, trying to help, not confuse.

I get that, don't worry

Do all possible numbers need entering into the list-I can't believe that would be the case?

No, I showed you how to use the function (which is supposed to make your life easier). Despite the fact that said function is overkill given the typical data being numbers as strings "starting from 1 up to about 600" as you put it, I'll try to explain for completeness' sake.

Let's say the string you wish to test is "123". If it can be converted to a number you want to use it in a calculation, say multiply it by 2, returning the result to the caller, otherwise you want to tell the user the string could not be coerced to a number and return nil to the caller.

Code: [Select]
(progn

    (setq str "123")

    (if (setq num (_DistOf str))
        (* 2 num)
        (progn (princ (strcat "String \"" str "\" cannot be coerced to a number.")) nil)
    )

)

==> 246

Now try it again but pass string "ABC".

Code: [Select]
(progn

    (setq str "ABC")

    (if (setq num (_DistOf str))
        (* 2 num)
        (progn (princ (strcat "String \"" str "\" cannot be coerced to a number.")) nil)
    )

)

==> String "ABC" cannot be coerced to a number.nil

Put one more way ... using your own example from later in the thread:

This seems to be using the _distof function you originally posted?  It's *that* that I need explaining.  I understand that you need to run the test, then do something with the result, it's how the test is working that I don't understand.  Sorry

Instead of this:

Code: [Select]
(IF (numberp (READ txt))
    (SETQ txt2 (ATOI txt))
)

So this will work?


All you would have to do is this:

Code: [Select]
(if (setq num (_DistOf txt))
    (Do_Something_With_Num num)
)
Except that, unless I've really gotten the wrong end of the stick, that's not all you need to do.  You need the mysterious _Distof function first.


PS: Using a variable named txt2 to represent a numerical value isn't advisable from a documentation perspective.

Very true, that's one of the things that's changing as I rework the routine.

I can find evidence that VL-SOME is an autolisp function,  but nothing to suggest what it might do.

It's in the AutoLISP Reference:

      Checks whether the predicate (the test) is not nil for (at least) one element combination.

In layman's terms it means the function will return true (and immediately stop processing) if one of the list items produces a non nil result when used in the test function, otherwise it will return nil.
I must admit I tend to avoid the AutoLISP reference, it tends to say things like that that don't say what the function's supposed to do.  Can it be used on a non-list?

What do FIXED and RESULT need to be set to?

"You" don't need to set them to anything, they are variables local to the _DistOf function, and are set / used by same.

How do distof, x, and base get generated?  I assume one of them is the test string?

Same as preceding comment.

HTH.

So just trust the magic ^_^

Sorry if that sounds overly negative, but I instictively don't like using stuff that just pop in and out of existence without my understanding them.


I know you're trying to help, so thankyou.

dJE
Title: Re: How lisp tell if a string is a number?
Post by: ElpanovEvgeniy on March 25, 2009, 05:32:26 AM
What is the number kept as a string?
"1e-3" - number?
"pi" - number?
" 1" - number?
"1 " - number?
" 1 " - number?
".1" - number?
"1." - number?
"1.1" - number?
"a1" - number?
"1a" - number?
"a1a" - number?
"1a1" - number?
"(1+ 2)" - number?

Title: Re: How lisp tell if a string is a number?
Post by: MP on March 25, 2009, 07:26:00 AM
I must admit I tend to avoid the AutoLISP reference ...

And thus ends my participation.
Title: Re: How lisp tell if a string is a number?
Post by: MP on March 25, 2009, 07:43:59 AM
What is the number kept as a string?
"1e-3" - number?
"pi" - number?
" 1" - number?
"1 " - number?
" 1 " - number?
".1" - number?
"1." - number?
"1.1" - number?
"a1" - number?
"1a" - number?
"a1a" - number?
"1a1" - number?
"(1+ 2)" - number?

Using evaluate (http://www.theswamp.org/index.php?topic=7259.msg89772#msg89772) from this thread ...

Code: [Select]
(defun evaluate ( expression / result )
    (setq result
        (vl-catch-all-apply
           '(lambda ( )
                (eval
                    (if (eq 'str (type expression))
                        (read expression)
                        expression
                    )
                )
            )
        )
    )   
    result
)

Code: [Select]
(setq candidates
    '(
        "1e-3"   
        "pi"     
        " 1"     
        "1 "     
        " 1 "   
        ".1"     
        "1."     
        "1.1"   
        "a1"     
        "1a"     
        "a1a"   
        "1a1"   
        "(1+ 2)"
    )   
)

Code: [Select]
(foreach candidate candidates
    (princ (setq text (vl-string-trim " " candidate)))
    (princ (substr "       " 1 (- 6 (strlen text))))
    (princ " ... ")
    (princ (evaluate candidate))
    (princ "\n")
    (princ)
)

Result
Code: [Select]
1e-3   ... 0.001
pi     ... 3.14159
1      ... 1
1      ... 1
1      ... 1
.1     ... #<%catch-all-apply-error%>
1.     ... 1.0
1.1    ... 1.1
a1     ... nil
1a     ... nil
a1a    ... nil
1a1    ... nil
(1+ 2) ... 3

With very little effort it could be made far more robust, but alas my interest in this thread wanes.

Title: Re: How lisp tell if a string is a number?
Post by: ElpanovEvgeniy on March 25, 2009, 08:11:29 AM
(atoi ".1");=>> 0
(atof ".1");=>> 0.1
Title: Re: How lisp tell if a string is a number?
Post by: ElpanovEvgeniy on March 25, 2009, 08:14:06 AM
(atoi ".");=>> 0
(atof ".");=>> 0.0