IsNumeric Function
IsNumeric Function
Gibt es eine Funktion, welche testet ob ein String ein numerischer Wert ist auch welchen Typs
wie z.B. Integer, Float, Hex oder binär?
etwa so
sTxt.s = "1.23"
If IsNumeric(sTxt) = #IsFloat
MyValue.d = ValD(sTxt)
ElseIf IsNumeric(sTxt) = #IsINT
MyValue.i = Val(sTxt)
Endif
wie z.B. Integer, Float, Hex oder binär?
etwa so
sTxt.s = "1.23"
If IsNumeric(sTxt) = #IsFloat
MyValue.d = ValD(sTxt)
ElseIf IsNumeric(sTxt) = #IsINT
MyValue.i = Val(sTxt)
Endif
Re: IsNumeric Function
Gibt es leider nicht
Auch wenn es einige Beispiel gibt, habe ich diese mal neu geschrieben
Update v1.02.2
- Erlaubt Zeichen nach Zahl (wie PB)
- Erlaubt Leerzeichen vor Zahl (wie PB)
- Regeln verschärft (Strenger wie PB)
Auch wenn es einige Beispiel gibt, habe ich diese mal neu geschrieben
Update v1.02.2
- Erlaubt Zeichen nach Zahl (wie PB)
- Erlaubt Leerzeichen vor Zahl (wie PB)
- Regeln verschärft (Strenger wie PB)
Code: Alles auswählen
;-TOP by mk-soft, v1.02.2, 12.11.2022
Enumeration 1
#IsInteger
#IsFloat
EndEnumeration
Procedure IsNumeric(Value.s)
Protected r1, *value.character, signed, num, float, exponent, exponent2
*value = @Value
If *value
Repeat
If *value\c = '+' Or *value\c = '-'
If signed
num = #False
Break
EndIf
signed = #True
ElseIf *value\c >= '0' And *value\c <= '9'
num = #True
Break
ElseIf *value\c <> ' '
Break
EndIf
*value + SizeOf(character)
ForEver
If num
Repeat
*value + SizeOf(character)
If *value\c = 0
Break
EndIf
If *value\c = '.'
float = 1
Break
ElseIf *value\c = 'e' Or *value\c = 'E'
exponent = 1
Break
ElseIf *value\c < '0' Or *value\c > '9'
Break
EndIf
ForEver
If float
Repeat
*value + SizeOf(character)
If *value\c >= '0' And *value\c <= '9'
float + 1
ElseIf *value\c = 'e' Or *value\c = 'E'
exponent = 1
Break
Else
Break
EndIf
ForEver
EndIf
If exponent
Repeat
*value + SizeOf(character)
If *value\c >= '0' And *value\c <= '9'
exponent + 1
ElseIf *value\c = '+' Or *value\c = '-'
If exponent >= 2
Break
ElseIf exponent2
num = #False
Break
EndIf
exponent2 = #True
Else
Break
EndIf
ForEver
EndIf
If num
If float And float < 2
r1 = 0
ElseIf exponent And exponent < 2
r1 = 0
Else
If float
r1 = #IsFloat
Else
r1 = #IsInteger
EndIf
EndIf
EndIf
EndIf
EndIf
ProcedureReturn r1
EndProcedure
; ****
CompilerIf #PB_Compiler_IsMainFile
Define t1.s
Debug "Numbers"
t1 = " 50"
Debug t1 + " = Type " + IsNumeric(t1) + " Value = " + ValF(t1)
t1 = "1000"
Debug t1 + " = Type " + IsNumeric(t1) + " Value = " + Val(t1)
t1 = "+1000 Meters"
Debug t1 + " = Type " + IsNumeric(t1) + " Value = " + Val(t1)
t1 = "-1000"
Debug t1 + " = Type " + IsNumeric(t1) + " Value = " + Val(t1)
t1 = "1.1"
Debug t1 + " = Type " + IsNumeric(t1) + " Value = " + ValF(t1)
t1 = "+100.0%"
Debug t1 + " = Type " + IsNumeric(t1) + " Value = " + ValF(t1)
t1 = "-100.0%"
Debug t1 + " = Type " + IsNumeric(t1) + " Value = " + ValF(t1)
t1 = "1E3"
Debug t1 + " = Type " + IsNumeric(t1) + " Value = " + ValF(t1)
t1 = "1.0e3+2"
Debug t1 + " = Type " + IsNumeric(t1) + " Value = " + ValF(t1)
t1 = "-0.1E+5+"
Debug t1 + " = Type " + IsNumeric(t1) + " Value = " + ValF(t1)
t1 = "-1.0e-3"
Debug t1 + " = Type " + IsNumeric(t1) + " Value = " + ValF(t1)
Debug "Invalid Numbers"
t1 = ".100"
Debug t1 + " = Type " + IsNumeric(t1) + " Value = " + ValF(t1)
t1 = "100."
Debug t1 + " = Type " + IsNumeric(t1) + " Value = " + ValF(t1)
t1 = "++100"
Debug t1 + " = Type " + IsNumeric(t1) + " Value = " + ValF(t1)
t1 = "--100"
Debug t1 + " = Type " + IsNumeric(t1) + " Value = " + ValF(t1)
t1 = "100..0"
Debug t1 + " = Type " + IsNumeric(t1) + " Value = " + ValF(t1)
t1 = "s100.0"
Debug t1 + " = Type " + IsNumeric(t1) + " Value = " + ValF(t1)
t1 = "2E"
Debug t1 + " = Type " + IsNumeric(t1) + " Value = " + ValF(t1)
t1 = "1.0ee-3"
Debug t1 + " = Type " + IsNumeric(t1) + " Value = " + ValF(t1)
t1 = "1.0e+-3"
Debug t1 + " = Type " + IsNumeric(t1) + " Value = " + ValF(t1)
t1 = ""
Debug t1 + " = Type " + IsNumeric(t1) + " Value = " + ValF(t1)
CompilerEndIf
Zuletzt geändert von mk-soft am 12.11.2022 21:05, insgesamt 7-mal geändert.
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
- jacdelad
- Beiträge: 348
- Registriert: 03.02.2021 13:39
- Computerausstattung: Ryzen 5800X, 108TB Festplatte, 32GB RAM, Radeon 7770OC
- Wohnort: Riesa
- Kontaktdaten:
Re: IsNumeric Function
Code: Alles auswählen
If Str(Val(String$))=String$
PureBasic 6.11/XProfan X4a/Embarcadero RAD Studio 11/Perl 5.2/Python 3.10
Windows 11/Ryzen 5800X/32GB RAM/Radeon 7770 OC/3TB SSD/11TB HDD
Synology DS1821+/36GB RAM/150TB
Synology DS920+/20GB RAM/54TB
Synology DS916+ii/8GB RAM/12TB
Windows 11/Ryzen 5800X/32GB RAM/Radeon 7770 OC/3TB SSD/11TB HDD
Synology DS1821+/36GB RAM/150TB
Synology DS920+/20GB RAM/54TB
Synology DS916+ii/8GB RAM/12TB
Re: IsNumeric Function
Not work with Zero and Floats
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
- jacdelad
- Beiträge: 348
- Registriert: 03.02.2021 13:39
- Computerausstattung: Ryzen 5800X, 108TB Festplatte, 32GB RAM, Radeon 7770OC
- Wohnort: Riesa
- Kontaktdaten:
Re: IsNumeric Function
Bei vielen einfachen Verwendungen sollte es reichen.
Wie wäre es ansonsten mit RegEx:
Wie wäre es ansonsten mit RegEx:
Code: Alles auswählen
^-?[0-9]\d*(\.\d+)?$
PureBasic 6.11/XProfan X4a/Embarcadero RAD Studio 11/Perl 5.2/Python 3.10
Windows 11/Ryzen 5800X/32GB RAM/Radeon 7770 OC/3TB SSD/11TB HDD
Synology DS1821+/36GB RAM/150TB
Synology DS920+/20GB RAM/54TB
Synology DS916+ii/8GB RAM/12TB
Windows 11/Ryzen 5800X/32GB RAM/Radeon 7770 OC/3TB SSD/11TB HDD
Synology DS1821+/36GB RAM/150TB
Synology DS920+/20GB RAM/54TB
Synology DS916+ii/8GB RAM/12TB
Re: IsNumeric Function
Das ist leider nicht so ganz trivial wie das zuerst aussieht, hab auch schon eine Weile rumprobiert.
Alle Beispiele die man so findet haben leider ihre Schwächen. Ich hab mittlerweile auch ne Version
programmiert. Hat aber auch diverse Schwächen und ist zu kompliziert geworden. D.h. man versteht
das nicht mehr, wenn man das nach Wochen erweitern möchte.
Der Absatz von mk.soft hat mich aber auf eine bessere Idee gebracht. Nämlich die Zeichen nicht
allgemein zu parsen, und dann mit einer Menge IF und Case das für die verschiedenen Möglichkeiten
zu zerlegen, sondern jedes Zeichen , mehrmals immer für den gewünschten Typ zu parsen.
Das gibt weit mehr als eine Funktion - das wird ein komplettes Modull
Reglar Expressions, darüber hab ich auch schon nachgedacht! Hat aber einen Hacken. Das bringt
nur #True/#False für die Übereinstimmung mit einem Schema. Ich hätte das aber gerne erweitert,
so dass man die Fehlerstelle ausweisen kann. Z.B. zweites Komma oder falsches Zeichen.
ich hab den Ansatz von mk-Soft mal einem Testlauf durchgeführt, das erkennt noch alles mögliche als
korrekt: (gleiches Probelm hatte ich bei meinem Code auch)
======================================
'-' : Not Numeric :
'+' : Not Numeric :
'' : Not Numeric :
'-12.003e-3' : IsFloat :
'12e3' : IsINT :
'12e+3' : IsINT :
'12E+3' : IsINT :
'+12.003e-3' : IsFloat :
'+123e-3+2' : IsINT :
'12.003e-3' : IsFloat :
'-12.003E+03' : IsFloat :
'-12.003E+' : Not Numeric :
'-12.003E' : Not Numeric :
'0123456789' : IsINT :
'0001234567' : IsINT :
' 12345' : IsINT :
'12345 ' : IsINT :
'12 345' : IsINT :
'12-345' : IsINT :
'12+34-5' : IsINT :
'12+345e+34-5' : IsINT :
=========================================
Mein Problem geht aber noch etwa weiter.
Ich muss HEX und Binärwerte mit und ohne PreFix erkennen können,
evtl 1000er Punkte bei Währungswerten.
Die momentane Idee ist, am Anfang alle Möglichkeiten auf TRUE zu setzen
#IsInt, IsFloat, IsHex, IsBin, IsCurrency ...
dann das Zeichen für Zeichen zu parsen und die FLAGs zurücksetzen,
die es nicht mehr sein können. Sobald ich einen vernüftigen CodeAnsatz habe,
werde ich den hier mal Posten, dann hat bestimmt jemand noch gute Ideen
Danke erst mal!
Alle Beispiele die man so findet haben leider ihre Schwächen. Ich hab mittlerweile auch ne Version
programmiert. Hat aber auch diverse Schwächen und ist zu kompliziert geworden. D.h. man versteht
das nicht mehr, wenn man das nach Wochen erweitern möchte.
Der Absatz von mk.soft hat mich aber auf eine bessere Idee gebracht. Nämlich die Zeichen nicht
allgemein zu parsen, und dann mit einer Menge IF und Case das für die verschiedenen Möglichkeiten
zu zerlegen, sondern jedes Zeichen , mehrmals immer für den gewünschten Typ zu parsen.
Das gibt weit mehr als eine Funktion - das wird ein komplettes Modull
Reglar Expressions, darüber hab ich auch schon nachgedacht! Hat aber einen Hacken. Das bringt
nur #True/#False für die Übereinstimmung mit einem Schema. Ich hätte das aber gerne erweitert,
so dass man die Fehlerstelle ausweisen kann. Z.B. zweites Komma oder falsches Zeichen.
ich hab den Ansatz von mk-Soft mal einem Testlauf durchgeführt, das erkennt noch alles mögliche als
korrekt: (gleiches Probelm hatte ich bei meinem Code auch)
======================================
'-' : Not Numeric :
'+' : Not Numeric :
'' : Not Numeric :
'-12.003e-3' : IsFloat :
'12e3' : IsINT :
'12e+3' : IsINT :
'12E+3' : IsINT :
'+12.003e-3' : IsFloat :
'+123e-3+2' : IsINT :
'12.003e-3' : IsFloat :
'-12.003E+03' : IsFloat :
'-12.003E+' : Not Numeric :
'-12.003E' : Not Numeric :
'0123456789' : IsINT :
'0001234567' : IsINT :
' 12345' : IsINT :
'12345 ' : IsINT :
'12 345' : IsINT :
'12-345' : IsINT :
'12+34-5' : IsINT :
'12+345e+34-5' : IsINT :
=========================================
Mein Problem geht aber noch etwa weiter.
Ich muss HEX und Binärwerte mit und ohne PreFix erkennen können,
evtl 1000er Punkte bei Währungswerten.
Die momentane Idee ist, am Anfang alle Möglichkeiten auf TRUE zu setzen
#IsInt, IsFloat, IsHex, IsBin, IsCurrency ...
dann das Zeichen für Zeichen zu parsen und die FLAGs zurücksetzen,
die es nicht mehr sein können. Sobald ich einen vernüftigen CodeAnsatz habe,
werde ich den hier mal Posten, dann hat bestimmt jemand noch gute Ideen
Danke erst mal!
- NicTheQuick
- Ein Admin
- Beiträge: 8679
- Registriert: 29.08.2004 20:20
- Computerausstattung: Ryzen 7 5800X, 32 GB DDR4-3200
Ubuntu 22.04.3 LTS
GeForce RTX 3080 Ti - Wohnort: Saarbrücken
- Kontaktdaten:
Re: IsNumeric Function
Richtig "witzig" wird das erst, wenn du das jetzt noch für verschiedene Länder haben willst. Weil überall andere Zeichen benutzt werden, andere Trennzeichen, usw.
Beispiel: "123,456"
Nach en_US wäre das: 123456
Nach de_DE wäre das: 123.456
Nach de_CH wäre das: NaN/Error
Hab das mal mit Python verifiziert:
Wenn du unterscheiden willst, ob etwas binär, hexadezimal oder dezimal ist, dann kann man das natürlich nie sicher machen, da zum Beispiel die Zahl 101 alles sein kann.
Beispiel: "123,456"
Nach en_US wäre das: 123456
Nach de_DE wäre das: 123.456
Nach de_CH wäre das: NaN/Error
Hab das mal mit Python verifiziert:
Code: Alles auswählen
>>> import locale
>>> locale.setlocale(locale.LC_ALL, 'en_US.utf8')
'en_US.utf8'
>>> locale.atof("123,456")
123456.0
>>> locale.setlocale(locale.LC_ALL, 'de_DE.utf8')
'de_DE.utf8'
>>> locale.atof("123,456")
123.456
>>> locale.setlocale(locale.LC_ALL, 'de_CH.utf8')
'de_CH.utf8'
>>> locale.atof("123,456")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.10/locale.py", line 338, in atof
return func(delocalize(string))
ValueError: could not convert string to float: '123,456'
Re: IsNumeric Function
Ja, das ist echt Sch....!
da es ja nicht nur ein Typ sein kann z.B. 1001 (Binär, Hex, Integer), ist das in einer Funktion
nicht umzusetzen. Auch mein Ansatz mit den Bools je Typ auf TRUE und dann StepByStep
rücksetzen was es nicht ist, führt in das gleiche If-Else Caos. Man kann das einfach später
nicht mehr nachvollziehen und somit auch nicht einfach anpassen.
Der im Moment für mich einzig vernünftige Ansatz ist, für jeden Typ einen eigene Parser-Funktion
IsInt(), IsFloat(), IsBin(), IsHex() und das dann eben nacheinander aufgerufen.
Die IsInteger() Funktion hab ich bereits , so nach dem Schema werd ich das auch für die anderen
Typen machen. Damit bleibt das nachvollziehbar.
Achtung noch nicht 100% getestet! Kann noch Fehler haben!
da es ja nicht nur ein Typ sein kann z.B. 1001 (Binär, Hex, Integer), ist das in einer Funktion
nicht umzusetzen. Auch mein Ansatz mit den Bools je Typ auf TRUE und dann StepByStep
rücksetzen was es nicht ist, führt in das gleiche If-Else Caos. Man kann das einfach später
nicht mehr nachvollziehen und somit auch nicht einfach anpassen.
Der im Moment für mich einzig vernünftige Ansatz ist, für jeden Typ einen eigene Parser-Funktion
IsInt(), IsFloat(), IsBin(), IsHex() und das dann eben nacheinander aufgerufen.
Die IsInteger() Funktion hab ich bereits , so nach dem Schema werd ich das auch für die anderen
Typen machen. Damit bleibt das nachvollziehbar.
Achtung noch nicht 100% getestet! Kann noch Fehler haben!
Code: Alles auswählen
Procedure IsInteger(sTxt.s)
; ============================================================================
; NAME: IsInteger
; DESC:
; VAR(sTxt.s): Text to test
; RET.i: If it is an Integer: Number of Digits, otherwise 0
; ============================================================================
Protected I, RET, Digits, c.c
Protected xSign, xNegativ, xSpaceAtEnd
Protected IsInt = #True
Protected *char.pChar ; Pointer to virtual CHAR-ARRAY
*char = @sTxt ; overlay the String with a virtual Char-Array
If Not *char ; If *Pointer to String is #Null
ProcedureReturn 0 ; ******** NotNumeric => EXIT PROCEDURE *********
EndIf
I = 0
; ----------------------------------------------------------------------
; Check for '+', '-' and skip Spaces
; ----------------------------------------------------------------------
While *char\c[I]
Select *char\c[I]
Case #IsNum_SPACE
Case '+'
xSign = #True
Case '-'
xSign = #True
xNegativ = #True
Break
Default
Break
EndSelect
I + 1 ; if we leave with Break, I is not inkremented
Wend
; ----------------------------------------------------------------------
; Parse Number - Check for Digits '0' to '9'
; ----------------------------------------------------------------------
While *char\c[I]
Select *char\c[I]
Case #IsNum_SPACE
xSpaceAtEnd=#True ; Space dedected : if it is not in the middle it is ok!
Break
Case '0' To '9'
Digits + 1 ; count Digits
Default ; any other Char is not allowed in an Integer
IsINT = #False ; Is not an Integer
Break
EndSelect
I + 1 ; Attention if we leave with break, I is not inkremented
Wend
; ----------------------------------------------------------------------
; Skip possible SPACEs at the end
; ----------------------------------------------------------------------
If xSpaceAtEnd
I + 1
While *char\c[I] ; if all Chars at end are Spaces it is ok
If *char\c[I] <> #IsNum_SPACE ; if any other Char follows after the Space, it is not an INT
IsINT = #False
EndIf
I + 1
Wend
EndIf
If IsInt
ProcedureReturn Digits ; if it is an Integer, return the number of Digits
Else
ProcedureReturn 0 ; otherwise 0
EndIf
EndProcedure
Re: IsNumeric Function
ohne den pCahr Type geht's nicht.
Das ist ein Pointer auf ein virtuelles Char-Array. Das gehört zu den undokumentierten Features von PB. Den Trick hab ich mir
im SourceCode der PB-IDE abgekuckt!
Das ist ein Pointer auf ein virtuelles Char-Array. Das gehört zu den undokumentierten Features von PB. Den Trick hab ich mir
im SourceCode der PB-IDE abgekuckt!
Code: Alles auswählen
Structure pChar ; virtual CHAR-ARRAY, used as Pointer to overlay on strings
c.c[0] ; fixed ARRAY Of CHAR Length 0
EndStructure
- juergenkulow
- Beiträge: 188
- Registriert: 22.12.2016 12:49
- Wohnort: :D_üsseldorf-Wersten
Re: IsNumeric Function
@SMaag Danke.
Code: Alles auswählen
; Feldzugriff auf Speicher
Structure pChar ; virtual CHAR-ARRAY, used as Pointer to overlay on strings
c.c[0] ; fixed ARRAY Of CHAR Length 0
EndStructure
Define *c.pChar=AllocateMemory(16)
*c\c[5]=33
; MOV rbp,qword [p_c]
; MOV word [rbp+10],33
; C Backend: p_c->f_c[5LL]=33;
; 000000014000110C | 48:8B05 05330000 | mov rax,qword ptr ds:[140004418] |
; 0000000140001113 | 66:C740 0A 2100 | mov word ptr ds:[rax+A],21 | 21:'!'
For i=0 To 7
ch.c=*c\c[i]
; MOV rbp,qword [p_c]
; PUSH rbp
; MOV rax,qword [v_i]
; ADD rax,rax
; POP rbp
; ADD rbp,rax
; MOVZX rax,word [rbp]
; MOV word [v_ch],ax
; C Backend: v_ch=p_c->f_c[v_i];
; 0000000140001135 | 48:8B05 DC320000 | mov rax,qword ptr ds:[140004418] |
; 000000014000113C | 48:8B15 DD320000 | mov rdx,qword ptr ds:[140004420] |
; 0000000140001143 | 0FB70450 | movzx eax,word ptr ds:[rax+rdx*2] |
; 0000000140001147 | 66:8905 E2320000 | mov word ptr ds:[140004430],ax |
s.s+RSet(Hex(ch),4,"0000")+" "
Next
Debug s
Debug Hex(*c\c[5])
ShowMemoryViewer(*c,16)