Page 1 of 4

IsNumber

Posted: Sat Sep 03, 2005 3:30 pm
by jack
please let me know if there's a better way

Code: Select all

Procedure IsNumber(String$)
  a$=Trim(UCase(String$))
  If a$=""
    ProcedureReturn 0
  EndIf
  number.l
  mantissa.l=0
  start.l=1
  char$=Mid(a$,1,1)
  
  If ((char$="+") Or (char$="-"))
    start=2
    If start>Len(a$)
      ProcedureReturn 0
    EndIf
  EndIf

  Repeat
    If start>Len(a$)
      Break
    EndIf
    char$=Mid(a$,start,1)
    start+1
    number=FindString("1234567890",char$,1)
    mantissa+1
  Until number=0

  If mantissa<2
    ProcedureReturn 0
  EndIf
  
  If (start-1)<Len(a$)
    If char$="."
      Repeat
        If start>Len(a$)
          Break
        EndIf
        char$=Mid(a$,start,1)
        start+1
        number=FindString("1234567890",char$,1)
      Until number=0
    EndIf
  EndIf

  If (start-1)<Len(a$)
    If char$="E"
      char$=Mid(a$,start,1)
      If ((char$="+") Or (char$="-"))
        start+1
      EndIf
      Repeat
        If start>Len(a$)
          Break
        EndIf
        char$=Mid(a$,start,1)
        start+1
        number=FindString("1234567890",char$,1)
      Until number=0
    EndIf
  EndIf
  
  If ((start-1)=Len(a$) And (number>0))
    number=1
  EndIf
  
  ProcedureReturn number
EndProcedure


Debug IsNumber("          -0.123456789e-7            ")
Debug IsNumber("e-7")

Posted: Sat Sep 03, 2005 4:08 pm
by Deeem2031

Code: Select all

a$=LTrim(UCase(s))
a$=RTrim(a$)
:?:

Code: Select all

a$=Trim(UCase(s))
:!:

Posted: Sat Sep 03, 2005 4:10 pm
by jack
yes your right. :)
<changed>

Posted: Sat Sep 03, 2005 4:14 pm
by Dare2
I would also be interested in a really fast way to do this.

This is what I use (for floats, use 1, for integers use 0 as 2nd param)

Code: Select all

Procedure isNumber(n.s,d.l)
  dp=0
  sn=0
  res=1
  w.s=Trim(n)
  If Left(w,1)="-" Or Left(w,1)="+"
    sn=1
  EndIf
  For i = sn+1 To Len(w)
    If FindString("0123456789.",Mid(w,i,1),1)=0
      res=0
      Break
    ElseIf Mid(w,i,1)="."
      dp+1
    EndIf
  Next
  If dp>d
    res=0
  EndIf
  ProcedureReturn res
EndProcedure

Debug isNumber("+12345.6789",1)    ; 1
Debug isNumber("-12345.6789",1)    ; 1
Debug isNumber("12345.6789+",1)    ; 0
Debug isNumber("123.45.6789+",1)   ; 0
Debug isNumber("123456789E-2",1)   ; 0 doesn't handle E+/-nnn
Debug isNumber("+123456789",0)     ; 1
Debug isNumber("-123456789",0)     ; 1
Debug isNumber("123456789+",0)     ; 0
But it doesn't check for overflow of bytes, words, longs nor for E/D notation nor for unrealistic floats.

Posted: Sat Sep 03, 2005 4:43 pm
by jack
maybe Psychophanta or El_Choni will come up with a fast asm routine :wink:

Posted: Sat Sep 03, 2005 4:58 pm
by Dare2
That would be neat.

Anyhow, your code improves on mine so I'm pinching bits of it. :)

Posted: Sat Sep 03, 2005 5:48 pm
by Deeem2031
jack wrote:maybe Psychophanta or El_Choni will come up with a fast asm routine :wink:
You want an asm routine? Here you are:

Code: Select all

Procedure IsNumber(s.s)
  !MOV Eax, dword[Esp] ;s
  !CMP byte[Eax], 0
  !JE l_asm_preturn
  s=Trim(s) 
  !MOV Eax, dword[Esp] ;s
  !XOR Edx, Edx
  
  !CMP byte[Eax], '+'
  !JE l_asm_p
  !CMP byte[Eax], '-'
  !JNE @f
  asm_p:
  !INC Eax
  !CMP byte[Eax], 0
  !JE l_asm_preturn
  !@@:
  
  !CMP byte[Eax], '0'
  !JB @f
  !CMP byte[Eax], '9'
  !JA @f
  !INC Eax
  !INC Edx ;number
  !CMP byte[Eax], 0
  !JNE @b
  !JMP l_asm_preturn_c
  !@@:
  
  !CMP byte[Eax], '.'
  !JNE l_asm_ndot
  !INC Eax
  !@@:
  !CMP byte[Eax], '0'
  !JB @f
  !CMP byte[Eax], '9'
  !JA @f
  !INC Eax
  !INC Edx ;number
  !CMP byte[Eax], 0
  !JNE @b
  !JMP l_asm_preturn_c
  !@@:
  
  asm_ndot:
  
  !OR byte[Eax], 0x20
  !CMP byte[Eax], 'e'
  !JNE l_asm_ne
  !INC Eax
  !CMP byte[Eax], '+'
  !JE l_asm_p2
  !CMP byte[Eax], '-'
  !JNE @f
  asm_p2:
  !INC Eax
  !CMP byte[Eax], 0
  !JE l_asm_preturn
  !@@:
  
  !CMP byte[Eax], '0'
  !JB @f
  !CMP byte[Eax], '9'
  !JA @f
  !INC Eax
  !INC Edx ;number
  !CMP byte[Eax], 0
  !JNE @b
  ;!JMP l_asm_preturn_c
  !@@:
  asm_ne:
  
  asm_preturn_c:
  !CMP byte[Eax], 0
  !MOV Eax, Edx
  !JNE l_asm_preturn
  !CMP Edx, 0
  !JLE l_asm_preturn
  !MOV Eax, 1
  asm_preturn:
  ProcedureReturn
EndProcedure 

Debug IsNumber("          -0.123456789e7            ") 
Debug IsNumber("++")
I hope everthing is correct.

Posted: Sat Sep 03, 2005 5:57 pm
by Pupil
I had nothing to do so i put together this:

Code: Select all

Procedure IsNumber(text.s)
DefType.l ret, dp
  *ptr.byte = @text
  If *ptr\b = 0
    ProcedureReturn 0
  EndIf
  
  While *ptr\b <> 0
    If *ptr\b >= '0' And *ptr\b <= '9'
      ret | 1
    ElseIf *ptr\b = '.'
      If dp : ProcedureReturn 0 : EndIf
      dp + 1 : ret = -2
    ElseIf *ptr\b = '+' Or *ptr\b = '-'
      If dp = 2
        dp+1
      ElseIf *ptr <> @text
        ProcedureReturn 0
      EndIf
    ElseIf *ptr\b = 'e' Or *ptr\b = 'E'
      If dp >= 2 Or (ret & 1 = 0) : ProcedureReturn 0 : EndIf
      dp = 2
      ret = -2
    Else
      ProcedureReturn 0
    EndIf
    *ptr+1
  Wend
  
  If ret & 1 = 0 : ProcedureReturn 0 : EndIf
  ProcedureReturn ret
EndProcedure
The procedure returns '1' if it's a valid integer number and '-1' if it's a valid float, '0' if it's not a valid number.

Maybe the routine needs a bit more testing as i only did a few testrounds with it :)

Posted: Sat Sep 03, 2005 6:33 pm
by jack
nice! :)

Posted: Sun Sep 04, 2005 12:02 pm
by Flype
Those codes might be used as a standard for the StringGadget([...],#PB_String_Numeric) allowing float values.
:roll:

Posted: Sun Sep 04, 2005 1:30 pm
by DarkDragon

Code: Select all

Procedure IsNumeric(text.s)
  text.s = Trim(UCase(text))
  If FindString(text, ".", 0)
  t.s = StrF(ValF(text.s))
  If t = Left(LSet(text.s, Len(t), "0"), Len(t))
  ProcedureReturn 1
  EndIf
  Else
  t.s = Str(Val(text.s))
  If t = text
  ProcedureReturn 1
  EndIf
  EndIf
EndProcedure

Debug IsNumeric("12")
Debug IsNumeric("-12.0345")
Debug IsNumeric("ABC")
Debug IsNumeric("AB.C")

Posted: Sun Sep 04, 2005 1:41 pm
by Dare2
:)

Good stuff here.

Posted: Sun Sep 04, 2005 1:57 pm
by PB
The shortest so far: ;)

Code: Select all

Procedure IsNumeric(t$)
  ok=1 : t$=Trim(t$)
  For p=1 To Len(t$)
    a=Asc(Mid(t$,p,1))
    If a<>45 And a<>46 And (a<48 Or a>57) : ok=0 : Break : EndIf
  Next
  ProcedureReturn ok
EndProcedure

Debug IsNumeric("12")
Debug IsNumeric("-12.0345")
Debug IsNumeric("ABC")
Debug IsNumeric("AB.C")

Posted: Sun Sep 04, 2005 2:37 pm
by thefool
neither of DarkDragons or pb's works: they should support this too:

Code: Select all

Debug IsNumber("          -0.123456789e-7            ")
Debug IsNumber("e-7") 
the reason is that it needs to support these strings as well. Like the "e"

Posted: Sun Sep 04, 2005 3:05 pm
by CodeMonkey
Don't forget that some countries use a coma ',' as decimal seperator this always catches me out when writing code for international markets. :?