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
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

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

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.
