Author Topic: Testing a string for a number  (Read 3809 times)

0 Members and 1 Guest are viewing this topic.

whdjr

  • Guest
Testing a string for a number
« on: April 24, 2006, 11:56:31 AM »
What would be a good and easy/quick way to test a string to see if it is a number?

(atoi "aaa")   ==> 0
(atoi "0")      ==> 0
(atoi "111")  ==> 111

Any ideas?

CAB

  • Global Moderator
  • Seagull
  • Posts: 10376
Re: Testing a string for a number
« Reply #1 on: April 24, 2006, 12:09:20 PM »
How about
Code: [Select]
(numberp (read (substr str 1 1)))or
Code: [Select]
(numberp (read str))
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

Alexander Rivilis

  • Bull Frog
  • Posts: 212
  • Programmer from Kyiv (Ukraine)
Re: Testing a string for a number
« Reply #2 on: April 24, 2006, 12:11:18 PM »
(distof "aaa")  ==> nil
(distof "0") ==> 0.0
(distof "111") ==> 111.0

T.Willey

  • Needs a day job
  • Posts: 5218
Re: Testing a string for a number
« Reply #3 on: April 24, 2006, 12:13:26 PM »
I think this might work.  Written on the fly.

Code: [Select]
(defun IsStrNums (String)

(and
 (mapcar
  '(lambda (x) (>= 48 x 57))
  (vl-string->list String)
 )
)
)

I think that is the right function to use (vl-string->list), but not sure.

Edit:  Change the test to greater than or equal, not less than or equal.
« Last Edit: April 24, 2006, 12:25:46 PM by T.Willey »
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

CAB

  • Global Moderator
  • Seagull
  • Posts: 10376
Re: Testing a string for a number
« Reply #4 on: April 24, 2006, 12:16:57 PM »
That's a nice one Rivilis. :-)
Code: [Select]
(distof "2'-3 1/2\"")
27.5
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

John Kaul (Se7en)

  • Administrator
  • Needs a day job
  • Posts: 9296
Re: Testing a string for a number
« Reply #5 on: April 24, 2006, 12:21:48 PM »
Oho, potential fun: I think if i remeber correctly numbers take up codes 48 and up in ascii codes. ... 0 = 48 1 = 49...

“Common sense is not so common.” ~Voltaire

--> Donate to TheSwamp.org <--

Alexander Rivilis

  • Bull Frog
  • Posts: 212
  • Programmer from Kyiv (Ukraine)
Re: Testing a string for a number
« Reply #6 on: April 24, 2006, 12:33:34 PM »
That's a nice one Rivilis. :-)
Code: [Select]
(distof "2'-3 1/2\"")
27.5
On my AutoCAD: (distof "2'-3 1/2\"") ==> nil because LUNITS is setting to 2
This function is dependent on LUNITS variable. If you need test only decimal number (not architectural, nor engineering)
you must use (distof val 2)  - val is a testing string.

MP

  • Seagull
  • Posts: 17525
Re: Testing a string for a number
« Reply #7 on: April 24, 2006, 01:23:11 PM »
On my AutoCAD: (distof "2'-3 1/2\"") ==> nil because LUNITS is setting to 2
This function is dependent on LUNITS variable. If you need test only decimal number (not architectural, nor engineering)
you must use (distof val 2)  - val is a testing string.

Perhaps this may be useful --

Code: [Select]
(defun MyDistOf ( string / result )
    (vl-some
       '(lambda (mode)
            (setq result
                (distof
                    string
                    mode
                )
            )
        )
       '(2 3 5 4 1)
    )
    result
)

From here.
\|// Set goal. Experiment tirelessly until
|Oo| practice has become expertise.  Loop.
|- | LinkedIn | Dropbox

whdjr

  • Guest
Re: Testing a string for a number
« Reply #8 on: April 24, 2006, 01:24:07 PM »
Thanks for the reply guys those are some great examples but I think for simplicity sake I will use the method suggested by CAB.

How about
...
Code: [Select]
(numberp (read str))

Thanks again guys,

MP

  • Seagull
  • Posts: 17525
Re: Testing a string for a number
« Reply #9 on: April 24, 2006, 01:33:12 PM »
I don't know the context you're going to use it Will but do be careful --

    Command: (numberp (read "123 abc")) => T

    Command: (numberp (mydistof "123 abc")) => nil


Should your host application consider "123 abc" a number?

\|// Set goal. Experiment tirelessly until
|Oo| practice has become expertise.  Loop.
|- | LinkedIn | Dropbox

whdjr

  • Guest
Re: Testing a string for a number
« Reply #10 on: April 24, 2006, 01:41:36 PM »
Thanks Michael, 

The list will either be a number or a string not both so I think the numberp will work fine.  Thanks for your code though it definitely covers all the bases.  :-)

whdjr

  • Guest
Re: Testing a string for a number
« Reply #11 on: April 24, 2006, 01:51:12 PM »
Michael,

Upon further trials:

    Command: (numberp (read "123 abc")) => T -> In the VLIDE it strips everything off after the space.

    Command: (numberp (read "123abc")) => Nil  If you remove the space then it nil's out.

Just FYI.
 :-)

MP

  • Seagull
  • Posts: 17525
Re: Testing a string for a number
« Reply #12 on: April 24, 2006, 01:58:25 PM »
Precisely why I posted that example Will.

An aside, here's another variant I wrote that is relatively bomb proof --

Code: [Select]
(defun distanceof ( x  / result )
   (vl-catch-all-apply
      '(lambda ()
           (vl-some
              '(lambda (units) (setq result (distof x units)))
               (list (getvar "lunits") 4 5 2 1)
           )
       )
   )   
   result
)

From here.

:)
\|// Set goal. Experiment tirelessly until
|Oo| practice has become expertise.  Loop.
|- | LinkedIn | Dropbox

whdjr

  • Guest
Re: Testing a string for a number
« Reply #13 on: April 24, 2006, 02:04:39 PM »
Thanks Michael,

I like that one a little better because once it catches a T it stops processing.  Very COOL.

Thanks,
 :-)

CAB

  • Global Moderator
  • Seagull
  • Posts: 10376
Re: Testing a string for a number
« Reply #14 on: April 24, 2006, 02:33:39 PM »
Thanks Michael..

Here is something to consider, although may not be relevant to Will.

Code: [Select]
Command: test1                             Command: test2                         
                                                                                   
*--> 3.5        gives number: 3.5          *--> 3.5        gives number: 3.5       
" type: " 2                                                                       
*--> 3 1/2      gives number: 3.5          *--> 3 1/2      gives number: 3.5       
" type: " 2                                                                       
*--> 3 1/2"     gives number: 3.5          *--> 3 1/2"     gives number: 3.5       
" type: " 3                                                                       
*--> 3 1/2'     gives number: 42.0         *--> 3 1/2'     gives number: 42.0     
" type: " 3                                                                       
*--> 3-1/2'     gives number: 42.0         *--> 3-1/2'     gives number: 42.0     
" type: " 3                                                                       
*--> 3'-1"      gives number: 37.0         *--> 3'-1"      gives number: 37.0     
" type: " 3                                                                       
*--> 3' -1"      gives number: 3             **  Invalid Number  **  3' -1"       
" type: " 6                                                                       
*--> 3'- 1"      gives number: 3             **  Invalid Number  **  3'- 1"       
" type: " 6                                                                       
*--> 3'-1       gives number: 37.0         *--> 3'-1       gives number: 37.0     
" type: " 3                                                                       
*--> 3' 1       gives number: 37.0         *--> 3' 1       gives number: 37.0     
" type: " 3                                                                       
*--> 3' 1"      gives number: 37.0         *--> 3' 1"      gives number: 37.0     
" type: " 3                                                                       
*--> 3' 1 1/2   gives number: 37.5         *--> 3' 1 1/2   gives number: 37.5     
" type: " 3                                                                       
*--> 3'-1-1/2   gives number: 37.5         *--> 3'-1-1/2   gives number: 37.5     
" type: " 3                                                                       
*--> 3' 1 1/2"  gives number: 37.5         *--> 3' 1 1/2"  gives number: 37.5     
" type: " 3                                                                       
*--> 3' 1.5     gives number: 37.5         *--> 3' 1.5     gives number: 37.5     
" type: " 3                                                                       
*--> 3' .5      gives number: 36.5         *--> 3' .5      gives number: 36.5     
" type: " 3                                                                       
*--> 3'.5      gives number: 36.5          *--> 3'.5      gives number: 36.5       
" type: " 3                                                                       
  **  Invalid Number  **  10-1               **  Invalid Number  **  10-1         
                                                                                   
*--> -10        gives number: -10.0        *--> -10        gives number: -10.0     
" type: " 2                                                                       
  **  Invalid Number  **  -10-1              **  Invalid Number  **  -10-1         
                                                                                   
*--> .5         gives number: 0.5          *--> .5         gives number: 0.5       
" type: " 2                                                                       
*--> 0.5        gives number: 0.5          *--> 0.5        gives number: 0.5       
" type: " 2                                                                       
*--> 5 -2       gives number: 5              **  Invalid Number  **  5 -2         
" type: " 6                                                                       
*--> 1/2        gives number: 0.5          *--> 1/2        gives number: 0.5       
" type: " 2                                                                       
*--> 1/2"       gives number: 0.5          *--> 1/2"       gives number: 0.5       
" type: " 3                                                                       
*--> 9 1/2      gives number: 9.5          *--> 9 1/2      gives number: 9.5       
" type: " 2                                                                       
*--> 1.55E+01   gives number: 15.5         *--> 1.55E+01   gives number: 15.5     
" type: " 2                                                                       
  **  Invalid Number  **  5A                 **  Invalid Number  **  5A           
                                                                                   
*--> 5 A        gives number: 5              **  Invalid Number  **  5 A           
" type: " 6




Code: [Select]
(defun c:test1 (/ txt txtlst num)
  (setq txtlst
         (list  "3.5       "   ; type:  2
                "3 1/2     "   ; type:  2 ?5
                "3 1/2\"    "  ; type:  4
                "3 1/2'    "   ; type:  4
                "3-1/2'    "   ; type:  4
                "3'-1\"     "  ; type:  4
                "3' -1\"     " ; Invalid Number
                "3'- 1\"     " ; Invalid Number
                "3'-1      "   ; type:  4
                "3' 1      "   ; type:  4
                "3' 1\"     "  ; type:  4
                "3' 1 1/2  "   ; type:  4
                "3'-1-1/2  "   ; type:  4
                "3' 1 1/2\" "  ; type:  4
                "3' 1.5    "   ; type:  4
                "3' .5     "   ; Invalid Number
                "3'.5     "    ; type   3
                "10-1      "   ; Invalid Number
                "-10       "   ; type:  2
                "-10-1     "   ; Invalid Number
                ".5        "   ; type:  2
                "0.5       "   ; type:  2
                "5 -2      "   ; type:  6
                "1/2       "   ; type:  2 ?5
                "1/2\"      "  ; type:  4
                "9 1/2     "   ; type:  2 ?5
                "1.55E+01  "   ; type:  2
                "5A        "   ; Invalid Number
                "5 A       "   ; type:  6
         )
  )
  (setq idx -1)

  ;;  distof will tollerate trailing spaces but not any other character
  ;;  therefore READ can be used to extract numbers followed by characters IF
  ;;  there is a space behing the number (read "12 A") = 12 (read "12a") = "12a"


  (while (< (setq idx (1+ idx)) (length txtlst))
    (setq txt (nth idx txtlst))
    ;;  must be tested in this order (2 1 5 4 3)
    ;; if you use (1 2 3 4 5) you will not get any 2 4 or 5 results
    ;;  further test result in inconsistancies with 3&4 and 5 types
    (cond ((setq num (distof txt 2))
           (setq typ 2)
          )
          ((setq num (distof txt 1))
           (setq typ 1)
          )
          ((setq num (distof txt 5))
           (setq typ 5)
          )
          ((setq num (distof txt 3))
           (setq typ 3)
          )
          ((setq num (distof txt 4))
           (setq typ 4)
          )
          ((setq num (read txt))
           (setq typ 6)
          ); get number if followed by a space "10 a" = 10
           ;; (read "10a") = "10a" so you must test result with
           ;;   (numberp "10a") results in 'not a number'
    )
    (if (numberp num) ;  Got a valid number
      (progn
        (prompt (strcat "\n*--> " txt " gives number: "))
        (princ num)
        (print " type: ")
        (princ typ)
      )
      (prompt (strcat "\n  **  Invalid Number  **  " txt))
    )
  )
  (princ)

)

test2
Code: [Select]
  (while (< (setq idx (1+ idx)) (length txtlst))
    (setq txt (nth idx txtlst))
   
    (setq num (distanceof txt))
    (if (numberp num) ;  Got a valid number
      (progn
        (prompt (strcat "\n*--> " txt " gives number: "))
        (princ num)
        (print)
      )
      (prompt (strcat "\n  **  Invalid Number  **  " txt))
    )
  )
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

CAB

  • Global Moderator
  • Seagull
  • Posts: 10376
Re: Testing a string for a number
« Reply #15 on: April 24, 2006, 02:38:02 PM »
PS This routine came from a thread, maybe in the old swamp, not sure.
And I think Stig was the author.
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

MP

  • Seagull
  • Posts: 17525
Re: Testing a string for a number
« Reply #16 on: April 24, 2006, 09:32:07 PM »
Thanks Alan, sure wish Stig posted more often.

Here's the output from a quickly bashed out pile of code (sorry, it's pretty ugly) --

Code: [Select]
3.5       -> 3.5
3 1/2     -> 3.5
3 1/2"    -> 3.5
3 1/2'    -> 42.0
3-1/2'    -> 42.0
3'-1"     -> 37.0
3' -1"    -> nil
3'- 1"    -> nil
3'-1      -> 37.0
3' 1      -> 37.0
3' 1"     -> 37.0
3' 1 1/2  -> 37.5
3'-1-1/2  -> 37.5
3' 1 1/2" -> 37.5
3' 1.5    -> 37.5
3' .5     -> 36.5
3'.5      -> 36.5
10-1      -> nil
-10       -> -10.0
-10-1     -> nil
.5        -> 0.5
0.5       -> 0.5
5 -2      -> nil
1/2       -> 0.5
1/2"      -> 0.5
9 1/2     -> 9.5
1.55E+01  -> 15.5
5A        -> nil
5 A       -> nil

Code: [Select]
(   (lambda ( strings / maxlen )
        (setq maxlen
            (apply 'max
                (mapcar 'strlen strings)
            )
        )
        (mapcar
           '(lambda ( string / padding )
                (setq padding " ")               
                (princ
                    (strcat
                        (substr
                            (progn
                                (while
                                    (<
                                        (strlen
                                            (setq padding
                                                (strcat
                                                    padding
                                                    padding
                                                )
                                            )
                                        )
                                        maxlen
                                    )
                                )
                                (strcat string padding)
                            )
                            1
                            maxlen
                        )
                        " -> "
                        (   (lambda ( x / result )
                                (vl-catch-all-apply
                                   '(lambda ( )
                                        (vl-some
                                           '(lambda ( units )
                                                (setq result
                                                    (distof x units)
                                                )
                                            )
                                           '(4 5 2 1)
                                        )
                                    )
                                )
                                (vl-prin1-to-string result)
                            )
                            string
                        )
                        "\n"
                    )
                )   
            )
            strings
        )
        (princ)
    )
   '(
        "3.5"
        "3 1/2"
        "3 1/2\""
        "3 1/2'"
        "3-1/2'"
        "3'-1\""
        "3' -1\""
        "3'- 1\""
        "3'-1"
        "3' 1"
        "3' 1\""
        "3' 1 1/2"
        "3'-1-1/2"
        "3' 1 1/2\""
        "3' 1.5"
        "3' .5"
        "3'.5"
        "10-1"
        "-10"
        "-10-1"
        ".5"
        "0.5"
        "5 -2"
        "1/2"
        "1/2\""
        "9 1/2"
        "1.55E+01"
        "5A"
        "5 A"
    )
)
\|// Set goal. Experiment tirelessly until
|Oo| practice has become expertise.  Loop.
|- | LinkedIn | Dropbox

CAB

  • Global Moderator
  • Seagull
  • Posts: 10376
Re: Testing a string for a number
« Reply #17 on: April 25, 2006, 12:34:13 AM »
Michael,
Your command of the language is astounding.
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

MP

  • Seagull
  • Posts: 17525
Re: Testing a string for a number
« Reply #18 on: April 25, 2006, 01:15:57 AM »
Thanks Alan, you are way too generous. I should have written it properly (i.e. read-able by others) but had about 5 minutes to knock it off. Normally I'd break a problem down to its constituent functions but I was real pressed for time; ergo the mess I posted. Don't have any more tine tonight either -- I'm struggling to post this as a sleeping pill slams my synapses; both of them.
\|// Set goal. Experiment tirelessly until
|Oo| practice has become expertise.  Loop.
|- | LinkedIn | Dropbox

Didge

  • Bull Frog
  • Posts: 211
Re: Testing a string for a number
« Reply #19 on: April 26, 2006, 06:10:41 AM »
A very interesting thread Guys, I've often required a fail-safe string to number function, but something meaty enough to extract numbers from the following types of strings without falling over.

"Cable 1.2m deep"  and  "Cable depth 1.2m" 

To the user either string is much the same as the other, but ATOF tends to be a touch more fussy in it's requirements. I guess a character by character evaluation is called for.
Think Slow......

MP

  • Seagull
  • Posts: 17525
Re: Testing a string for a number
« Reply #20 on: April 26, 2006, 07:47:28 AM »
Might be some tips you can glean in this thread.
\|// Set goal. Experiment tirelessly until
|Oo| practice has become expertise.  Loop.
|- | LinkedIn | Dropbox

CAB

  • Global Moderator
  • Seagull
  • Posts: 10376
Re: Testing a string for a number
« Reply #21 on: April 26, 2006, 11:22:07 AM »
Here is another thread of intrest http://www.theswamp.org/index.php?topic=3710.0
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

Didge

  • Bull Frog
  • Posts: 211
Re: Testing a string for a number
« Reply #22 on: April 26, 2006, 12:25:19 PM »
Many thanks for the links guys, consider that function well and truely in the bag :-)
Think Slow......