IsNumber

Share your advanced PureBasic knowledge/code with the community.
jack
Addict
Addict
Posts: 1358
Joined: Fri Apr 25, 2003 11:10 pm

IsNumber

Post 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")
Last edited by jack on Sat Sep 03, 2005 5:47 pm, edited 3 times in total.
User avatar
Deeem2031
Enthusiast
Enthusiast
Posts: 216
Joined: Sat Sep 20, 2003 3:57 pm
Location: Germany
Contact:

Post by Deeem2031 »

Code: Select all

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

Code: Select all

a$=Trim(UCase(s))
:!:
irc://irc.freenode.org/#purebasic
jack
Addict
Addict
Posts: 1358
Joined: Fri Apr 25, 2003 11:10 pm

Post by jack »

yes your right. :)
<changed>
Dare2
Moderator
Moderator
Posts: 3321
Joined: Sat Dec 27, 2003 3:55 am
Location: Great Southern Land

Post 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.
@}--`--,-- A rose by any other name ..
jack
Addict
Addict
Posts: 1358
Joined: Fri Apr 25, 2003 11:10 pm

Post by jack »

maybe Psychophanta or El_Choni will come up with a fast asm routine :wink:
Dare2
Moderator
Moderator
Posts: 3321
Joined: Sat Dec 27, 2003 3:55 am
Location: Great Southern Land

Post by Dare2 »

That would be neat.

Anyhow, your code improves on mine so I'm pinching bits of it. :)
@}--`--,-- A rose by any other name ..
User avatar
Deeem2031
Enthusiast
Enthusiast
Posts: 216
Joined: Sat Sep 20, 2003 3:57 pm
Location: Germany
Contact:

Post 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.
irc://irc.freenode.org/#purebasic
Pupil
Enthusiast
Enthusiast
Posts: 715
Joined: Fri Apr 25, 2003 3:56 pm

Post 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 :)
jack
Addict
Addict
Posts: 1358
Joined: Fri Apr 25, 2003 11:10 pm

Post by jack »

nice! :)
User avatar
Flype
Addict
Addict
Posts: 1542
Joined: Tue Jul 22, 2003 5:02 pm
Location: In a long distant galaxy

Post by Flype »

Those codes might be used as a standard for the StringGadget([...],#PB_String_Numeric) allowing float values.
:roll:
No programming language is perfect. There is not even a single best language.
There are only languages well suited or perhaps poorly suited for particular purposes. Herbert Mayer
DarkDragon
Addict
Addict
Posts: 2344
Joined: Mon Jun 02, 2003 9:16 am
Location: Germany
Contact:

Post 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")
bye,
Daniel
Dare2
Moderator
Moderator
Posts: 3321
Joined: Sat Dec 27, 2003 3:55 am
Location: Great Southern Land

Post by Dare2 »

:)

Good stuff here.
@}--`--,-- A rose by any other name ..
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Post 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")
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
thefool
Always Here
Always Here
Posts: 5875
Joined: Sat Aug 30, 2003 5:58 pm
Location: Denmark

Post 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"
CodeMonkey
User
User
Posts: 12
Joined: Tue Jul 12, 2005 6:55 pm
Location: United Kingdom

Post 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. :?
Post Reply