Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Brl.Blitz] string.ToInt(), .ToDouble() etc. - add option to identify "non numeric input" #346

Open
GWRon opened this issue Nov 24, 2024 · 1 comment

Comments

@GWRon
Copy link
Contributor

GWRon commented Nov 24, 2024

Heya,

Today I wrote some code to do extract a number from a given string.
For stuff like "[whitespace]1.2345[whitespace]" this works fine and converts fasts.

But in my case I want to compare a "(potentially) numeric string" with a given number (long, double, ...).
The current implementation of string.ToInt() and the likes do not tell the user, if the input string was number at all.

SuperStrict
Framework Brl.StandardIO

Print "0".ToInt()     '-> 0
Print "5".ToInt()     '-> 5
Print "123.3".ToInt() '-> 123
Print "".ToInt()      '-> 0
Print "hello".ToInt() '-> 0

Is there a way to add some parameter to "ToInt..." (like an overload) to retrieve if the input string contained something "else" than a number (so AZaz ... and the likes?

For now to achieve this one needs to check if the resulting number has the same "string representation" as the input string (trimmed)

    Local d:Double = double(s)
    If Abs(d) < 0.000001 '"hello world" became 0-check required
        if string(d) = s.trim() Then print "invalid number"
    Else
        print "number is " + d 
    EndIf

As this is done in BlitzMax, we create a new string (string(d)) and in case of an invalid conversion (Double("hello")) another one.

This is overhead I would like to seen avoided (aka an option is provided to see if a provided converted number bases on a valid "string number").

@GWRon
Copy link
Contributor Author

GWRon commented Dec 22, 2024

The new code contains "ToDoubleEx()" and the likes - which add further options and configurability.

Yet it still fails with values like 12asdsfsdf-32432" (ToLongEx()andlong(string)extract "12" here... which is incorrect). TolongEx() returns the position of the first non-long char (here the "a")) but it also returns the first whitespace position for"12 "` so you do not know if the given number is a valid long with whitespace, or just a alpha-num string which begun with numbers.

My "comparative" approaches use log10 (but there whitespace is not ignored) or ExtractNumber():

SuperStrict
Framework Brl.StandardIO
Import Brl.Retro


Local s:String = "12a-a1234"
Local l:Long = Long(s)
Local digits:Int
If l > 0
	digits = Int(Log10(l)) + 1
ElseIf l = 0
	digits = 1
Else
	digits = Int(Log10(-l)) + 2
EndIf


If digits <> s.Length
	Print "invalid long: " + s + " -> " + l
Else
	Print "valid long :" + s + " -> " + l
EndIf


Local l2:Long
If ExtractNumber(s, l2)
	Print "valid long : " + l2
Else
	Print "invalid long : " + s
EndIf

Function ExtractNumber:Int(s:String, longValue:Long Var)
	If s.Length = 0 Then Return 0 'no extraction happened
	
	longValue = 0
	
	Local negative:Int = 0
	Local decimalDivider:Long=10
    Local hasSpaceAfter:Int = 0
    Local hasDigits:Int = 0
    Local hasMinus:Int = 0
	Local index:Int = 0

    While index < s.Length
        Local charCode:Int = s[index]
		'only allow spaces once a space after a numeric value happened
        If hasSpaceAfter And charCode <> Asc(" ")
			Return 0 'invalid
		EndIf
		
		'extract number / decimals
        If (charCode >= 48 And charCode <= 57) '48 = "0", 57 = "9"
			longValue = longValue * 10 + (charCode-48)
			hasDigits = True
        ' allow minus at begin
        ElseIf charCode = Asc("-") And Not hasDigits
			hasMinus = True
        ' allow space at begin and end
        ElseIf charCode = Asc(" ")
			' if space at end - mark it
			If hasDigits
				hasSpaceAfter = True
			EndIf
		' invalid char found
        Else
			Return 0 'invalid
        EndIf
		index :+ 1 'processed 
    Wend

	If hasMinus
		longValue = -1 * longValue
	EndIf
	Return 1
End Function

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant