Seite 2 von 3

Re: isNumeric

Verfasst: 24.01.2015 19:21
von Nino
NicTheQuick hat geschrieben:Das Problem ist, dass du den Trick von Nino mit dem + "1" wieder raus genommen hast.
Der hatte nämlich verhindert, dass das hier funktioniert:

Code: Alles auswählen

Debug isNumeric("3a") ;ergibt 1
Und

Code: Alles auswählen

Debug isNumeric("0.0")
ergibt mit Tommys letztem Code fälschlicherweise 0.

In meinem Macro hat hingegen bisher noch niemand einen Fehler gefunden. :-)
(Und wer unbedingt will, kann ja das ReplaceString()-Gedöns davor schreiben.)

Re: isNumeric

Verfasst: 24.01.2015 20:17
von NicTheQuick
@Nino:
Deine Funktion ist auch nicht unschlagbar, wenn man nur genug Nachkommastellen dazu nimmt. ;)

Code: Alles auswählen

Debug IsNumeric("1.234567890123456") ; -> 0
Allerdings wäre sogar noch eine Stelle mehr mit Doubles darstellbar:

Code: Alles auswählen

d.d = 1.2345678901234567
Debug StrD(d, 16)

Re: isNumeric

Verfasst: 24.01.2015 20:41
von Nino
@NicTheQuick:
Vielen Dank, dass Du diesen Bug gefunden hast.

Ich habe jetzt ein ValD() durch ValF() ersetzt, und das andere ValD() stehen gelassen.
Nun funktioniert auch Dein Beispiel. :-)
Aber evtl. wird sich wieder ein anderes Beispiel finden lassen, wo's nicht funktioniert.

Re: isNumeric

Verfasst: 24.01.2015 21:00
von NicTheQuick
Und da wir schon dabei sind. Ich habe mich jetzt auch dazu hinreißen lassen etwas herum zu pointern. Ich hoffe ich habe an alles gedacht:

Code: Alles auswählen

Procedure.i isNumeric(value.s)
	Protected *c.Character = @value
	
	;Skip whitespaces
	While *c\c = ' ' Or *c\c = 9
		*c + SizeOf(Character)
	Wend
	
	;Skip Minus and Plus signs
	Protected i.i = 0
	While *c\c = '-' Or *c\c = '+'
		*c + SizeOf(Character)
		i + 1
	Wend
	If (i > 1) ; Error if more than one sign
		ProcedureReturn #False
	EndIf
	i = 0	
	
	Select *c\c
		Case '$'	; Hex
			Repeat
				i + 1
				*c + SizeOf(Character)
			Until Not ((*c\c >= '0' And *c\c <= '9') Or (*c\c >= 'a' And *c\c <= 'f') Or (*c\c >= 'A' And *c\c <= 'F'))
			i - 1
			
		Case '%'	; Binary
			Repeat
				i + 1
				*c + SizeOf(Character)
			Until *c\c <> '0' And *c\c <> '1'
			i - 1
			
		Case '0' To '9'	; Decimal
			Protected j = 0
			Repeat
				i + 1
				If (*c\c = '.')
					If (j = 1)	;Too many commas
						ProcedureReturn #False
					EndIf
					j + 1
				EndIf
				*c + SizeOf(Character)
			Until (*c\c < '0' Or *c\c > '9') And *c\c <> '.'
			
			If (i - j = 0) ; No digits
				ProcedureReturn #False
			EndIf
			
			If (*c\c = 'e' Or *c\c = 'E')	;Exponent
				*c + SizeOf(Character)
				
				;Skip Minus and Plus signs
				i = 0
				While *c\c = '-' Or *c\c = '+'
					*c + SizeOf(Character)
					i + 1
				Wend
				If (i > 1) ; Error if more than one sign
					ProcedureReturn #False
				EndIf
				
				While (*c\c >= '0' And *c\c <= '9')
					*c + SizeOf(Character)
					i + 1
				Wend
			EndIf
			
		Default
			ProcedureReturn #False
	EndSelect
	
	While *c\c = ' ' Or *c\c = 9
		*c + SizeOf(Character)
	Wend
	ProcedureReturn Bool(i And *c\c = 0)
EndProcedure

; ===  Test  ===
Debug "=== Numeric ==="
Debug IsNumeric("123")
Debug IsNumeric("1.23")
Debug IsNumeric("-1.234567890123456")
Debug IsNumeric("$FF")
Debug IsNumeric("-%101  ")
Debug IsNumeric("+1.7e-6")
Debug IsNumeric("0")
Debug IsNumeric("  -0.0")

Debug "=== Not Numeric ==="
Debug isNumeric("--12")
Debug isNumeric("12.45.6")
Debug isNumeric("%")
Debug isNumeric("$g")
Debug IsNumeric("12c")
Debug IsNumeric("12c")
Debug IsNumeric("abc")
Debug IsNumeric("")
'ValD()' akzeptiert übrigens auch Dezimalzahlen ohne Ziffern vor dem Komma. Falls das auch hier gewünscht ist, muss man lediglich aus

Code: Alles auswählen

Case '0' To '9'
das hier machen:

Code: Alles auswählen

Case '0' To '9', '.'

Re: isNumeric

Verfasst: 24.01.2015 21:26
von Nino
Sieht gut aus, und funktioniert hier einwandfrei.

Re: isNumeric

Verfasst: 24.01.2015 22:00
von NicTheQuick
Hier noch die RegEx-Variante, die genau das gleiche macht wie meine Pointervariante.

Code: Alles auswählen

Procedure.i IsNumeric(value.s)
	Static regex.i = 0
	If regex = 0
		;regex = CreateRegularExpression(#PB_Any, "^\s*(\+|-)?(\$[0-9a-fA-F]+|%[01]+|([0-9]+|[0-9]*\.[0-9]+)([eE](\+|-)?[0-9]+)?)\s*$", #PB_RegularExpression_MultiLine)
		regex = CreateRegularExpression(#PB_Any, "^\s*(\+|-)?(\$[[:xdigit:]]+|%[01]+|(\d+|\d*\.\d+)([eE](\+|-)?\d+)?)\s*$", #PB_RegularExpression_MultiLine)
	EndIf
	ProcedureReturn MatchRegularExpression(regex, value)
EndProcedure

; ===  Test  ===
Debug "=== Numeric ==="
Debug IsNumeric("123")
Debug IsNumeric("1.23")
Debug IsNumeric("-1.234567890123456")
Debug IsNumeric("$FF")
Debug IsNumeric("-%101  ")
Debug IsNumeric("+1.7e-6")
Debug IsNumeric("0")
Debug IsNumeric("  -0.0")
Debug isNumeric(".123")

Debug "=== Not Numeric ==="
Debug isNumeric("--12")
Debug isNumeric("12.45.6")
Debug isNumeric("%")
Debug isNumeric("$g")
Debug IsNumeric("12c")
Debug IsNumeric("12c")
Debug IsNumeric("abc")
Debug IsNumeric("")
Debug IsNumeric("e14")
Edit: Ein paar Zeichen durch ihre Zeichenklasse ersetzt.

Re: isNumeric

Verfasst: 25.01.2015 00:20
von Vera
Tolle Beispiele ~ danke :D

Scharf find' ich die RegEx-Variante.

Frage: Wo findet man, welche Anteile der Rex-Ex-Ausdrücke PB-Syntax sind?

Re: isNumeric

Verfasst: 25.01.2015 00:30
von NicTheQuick
Vera hat geschrieben:Frage: Wo findet man, welche Anteile der Rex-Ex-Ausdrücke PB-Syntax sind?
Was meinst du damit? RegEx ist RegEx. Das hat nichts mit PB zu tun. Außer, dass man da RegEx eben nutzen kann. Alles weitere findest du bei Wiki - Regulärer Ausdruck.

Re: isNumeric

Verfasst: 25.01.2015 00:32
von Tommy
RegEx Variante finde ich auch am besten
aber unbedingt Lizenzbdingung beachten! Man muss glaube ich den Entwickler in seiner About nennen.

Re: isNumeric

Verfasst: 25.01.2015 00:45
von Nino
Besser nicht glauben oder raten, sondern lesen.