@Trond and Idle...
They reject several examples of exponential numbers...
for easy viewing.
Code: Select all
Structure SParseNumber
Input.s
Look.c
EndStructure
Procedure GetChar(*S.SParseNumber)
*S\Look = Asc(*S\Input)
*S\Input = Mid(*S\Input, 2)
EndProcedure
Procedure GetInteger(*S.SParseNumber)
Protected Result = 0
While *S\Look >= '0' And *S\Look <= '9'
Result = 1
GetChar(*S)
Wend
ProcedureReturn Result
EndProcedure
Procedure GetFloat(*S.SParseNumber)
; Returns:
; 0 = syntax error
; 1 = valid integer
; 2 = valid floating point
IsInt = GetInteger(*S)
If IsInt And *S\Look = '.' ; decimal point
GetChar(*S)
IsInt = GetInteger(*S)
If IsInt = 0
ProcedureReturn 0 ; syntax error
EndIf
ProcedureReturn 2
EndIf
ProcedureReturn IsInt
EndProcedure
Procedure GetNumberType(S.s)
; PureBasic Forum: Trond
; Returns:
; 0 = syntax error
; 1 = valid integer
; 2 = valid floating point, but not with exponent
; 3 = valid number in exponent format
N.SParseNumber
N\Input = S
GetChar(@N)
IsFloat = GetFloat(@N)
If IsFloat And N\Look = 'e'
GetChar(@N)
IsInt = GetInteger(@N)
If IsInt And N\Look = 0
ProcedureReturn 3
Else
ProcedureReturn 0
EndIf
EndIf
If N\Look = 0
ProcedureReturn IsFloat
Else
ProcedureReturn 0
EndIf
EndProcedure
Procedure.i IsNumeric(S.s)
; Check only for true numeric quantities.
; Formatted numbers using thousands separators or currency marks are
; treated as text and result in #false.
; Zero is the more complicated case.
Protected.d x
x = ValD(Trim(S))
If (x > 0 Or x < 0)
ProcedureReturn #True
Else ; Check for a real "0" case.
; not a string converted to 0
S = Trim(LCase(S))
If Len(s)=0 Or (Len(S)=1 And Asc(S)<>'0')
ProcedureReturn #False
Else
If FindString(S,"-",1) = 1 Or FindString(S,"+",1) = 1
S = Mid(S,2)
EndIf
S = Trim(S,"0")
If FindString(S,".",1) = 1
S = Mid(S,2)
S = Trim(S,"0")
If FindString(S,".",1)
ProcedureReturn #False
EndIf
EndIf
If FindString(S,"e",1)
If Len(S)=1
ProcedureReturn #True
EndIf
EndIf
If FindString(S,"e+",1) Or FindString(S,"e-",1)
If Len(S)=2
ProcedureReturn #True
EndIf
EndIf
If Len(S)
ProcedureReturn #False
Else
ProcedureReturn #True
EndIf
EndIf
EndIf
EndProcedure
Procedure.i isnumericRE(s.s)
; Or try using Regular Expressions...
; Can't get scientific notation to work :(
Protected.s RE
RE = "^(([0-9+-.$]{1})|([+-]?[$]?[0-9]*(([.]{1}[0-9]*)|([.]?[0-9]+))))$"
;RE = "[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?"
If CreateRegularExpression(0, RE)
If MatchRegularExpression(0, Trim(s))
ProcedureReturn #True
Else
ProcedureReturn #False
EndIf
Else
Debug RegularExpressionError()
EndIf
EndProcedure
Procedure IsNumericIdle(strexp.s)
; PureBasic Forum: Idle
Protected a,*valid = AllocateMemory(16)
For a = 0 To 9
PokeB(*valid+ct,(Asc(Str(a))))
ct+1
Next
PokeB(*valid+ct,Asc("."))
ct+1
PokeB(*valid+ct,Asc(","))
ct+1
PokeB(*valid+ct,Asc(":"))
ct+1
PokeB(*valid+ct,Asc("e"))
ct+1
PokeB(*valid+ct,Asc("$"))
ct+1
PokeB(*valid+ct,Asc("-"))
ct+1
PokeB(*valid+ct,Asc("+"))
ct+1
PokeB(*valid+ct,Asc(" "))
Protected b,len, *str,*pa.byte, *pb.byte
len = Len(strexp)
*str = @strexp
*val = *valid
a=0
While a < len
*pa = *str+a
b=0
While b < 18
*pb = *valid+b
If *pa\b = *pb\b
numeric = 1
Break
EndIf
b+1
Wend
If numeric
cat+1
numeric = 0
Else
Break
EndIf
a+1
Wend
FreeMemory(*valid)
If cat = len
ProcedureReturn 1
Else
ProcedureReturn 0
EndIf
EndProcedure
;-{ Load test examples
Dim T.s(50)
Define.i k,i,nsp
Define.s sp,r
Restore StringNumerics
Repeat
Read.s T(k)
If T(k) <> "#EOF"
If nsp<Len(T(k))
nsp = Len(T(k))+1
sp = Space(nsp)
EndIf
k = k + 1
EndIf
Until T(k) = "#EOF"
ReDim T(k-1)
;-}
Debug LSet("S",nsp) + LSet("ValD(S)",nsp) + LSet("IsNumeric(S)",nsp-6)
For i = 0 To k-1
Debug LSet(T(i),nsp) + LSet(StrD(ValD(T(i)),6),nsp) + LSet(Str(IsNumeric(T(i))),nsp-6)
Next i
Debug ""
Debug LSet("S",nsp) + LSet("ValD(S)",nsp) + LSet("IsNumericRE(S)",nsp-6)
For i = 0 To k-1
Debug LSet(T(i),nsp) + LSet(StrD(ValD(T(i)),6),nsp) + LSet(Str(IsNumericRE(T(i))),nsp-6)
Next i
Debug ""
Debug LSet("S",nsp) + LSet("ValD(S)",nsp) + LSet("GetNumberType(S)",nsp-6)
For i = 0 To k-1
Debug LSet(T(i),nsp) + LSet(StrD(ValD(T(i)),6),nsp) + LSet(Str(GetNumberType(T(i))),nsp-6)
Next i
Debug ""
Debug LSet("S",nsp) + LSet("ValD(S)",nsp) + LSet("IsNumericIdle(S)",nsp-6)
For i = 0 To k-1
Debug LSet(T(i),nsp) + LSet(StrD(ValD(T(i)),6),nsp) + LSet(Str(IsNumericIdle(T(i))),nsp-6)
Next i
DataSection
StringNumerics:
; S ValD(S) IsNumeric(S)
Data.s "" ; 0.0 0
Data.s " " ; 0.0 0
Data.s "0" ; 0.0 1
Data.s "0.0" ; 0.0 1
Data.s "+0e0" ; 0.0 1
Data.s "+0.0e0" ; 0.0 1
Data.s "+0.0e+0" ; 0.0 1
Data.s "+0.0e0e0" ; 0.0 0
Data.s "+0.0e-0e0" ; 0.0 0
Data.s "+0.0e+0e+0" ; 0.0 0
Data.s "e" ; 0.0 0
Data.s "e12" ; 0.0 0
Data.s " 99" ; 99.0 1
Data.s "-99 " ; -99.0 1
Data.s "99" ; 99.0 1
Data.s "ABC" ; 0.0 0
Data.s "AB99CD" ; 0.0 0
Data.s "0000899" ; 899.0 1
Data.s "0A00899" ; 0.0 0
Data.s "1.64e-6" ; 1.64e-6 1
Data.s "3,000" ; 3.0 1
Data.s "0 12" ; 0.0 0
Data.s "134.23e" ; 134.23 1
Data.s "0123456789 -+e:$.," ; 123456789.0 1
Data.s "0123456789 A" ; 123456789.0 1
Data.s "3,100,000.01a" ; 3.0 1
Data.s "3.100.000,01b" ; 3.1 1
Data.s "b3.000.000,01" ; 0.0 0
Data.s "3z,200,000.01" ; 3.0 1
Data.s "3x.200.000,01" ; 3.0 1
Data.s "$100.123" ; 0.0 0
Data.s "#EOF"
EndDataSection