hal9k
Junior Member
Posts: 87
|
Post by hal9k on Oct 11, 2022 13:38:11 GMT -5
Is there a good way to do a numeric test? I couldn't find one, so I wrote this "brute force" function, but I suspect there is a better way.
Thanks!
FUNCTION FN.IsNumeric(String$) 'This function returns 1 if the string is numeric FN.IsNumeric = 1 'let's assume it's numeric FOR i = 1 TO LEN(String$) test = ASC(MID$(String$, i, 1)) IF test < 48 OR test > 57 THEN FN.IsNumeric = 0 EXIT FOR END IF NEXT i END FUNCTION
|
|
|
Post by Walt Decker on Oct 11, 2022 13:49:56 GMT -5
How about:
FUNCTION FN.IsNumeric(StrIn$)
True = 1 NumStr$ = ""
NumStr$ = STR$(VAL(StrIn$))
IF LEN(NumStr$) < LEN(StrIn$) THEN EXIT FUNCTION END IF FN.IsNumeric = True END FUNCTION
Your function does not consider the possibility of a decimal number.
Also, you could compare each byte to the magic string "-+0123456789." and save a bit of conversion.
|
|
|
Post by tsh73 on Oct 11, 2022 14:26:50 GMT -5
It really depend on how numeric it will be. If you want to check if string makes valid number (including floating point and scientific notation), have a look at this program from old 2008 contest.
(here, function isNumber uses auxiliary function eatUp below it)
'v. 02 - now start my own func data "valid" data "0", "0.", "0.0", "1.0" data "1", "-1", "123","-123" data "1.", ".1", "1.1" data "-1.", "-.1", "-1.1" data "1e2", ".1e2", "1.1e2" data "1e-2", ".1e-2", "1.1e-2" data "-1e-2", "-.1e-2", "-1.1e-2" data "0.0000000001", "7987987987987987", "7987987987987987.3", "1.03e-41" data "not valid" data "." 'actually JB consider it 0.0 -?? data "1 2", "- 1", "--1" data "1e", "1d2", "1-2", "1e2.5" data "1.2^2", "1.2+3" 'data "1ee2" 'specially for my function 'data "1e1000" 'float overlow if you try to VAL() it data "over"
global True, False False = 0 True = 1 dim failed(True), passed(True)
read input$ while 1 input$ = trim$(input$) 'just for the case select case input$ case "valid" goal = True print "Checking VALID" case "not valid" 'first report progress so far print "Passed: ";passed(goal);" Failed: ";failed(goal) goal = False print "Checking NOT VALID" case "over" exit while case else 'print input$, goal print input$, 'res = check1(input$) 'res = check2(input$) 'res = check3(input$) res = IsNumber(input$) 'print res, if res = goal then passed(goal)= passed(goal)+1 print "Passed" else failed(goal)= failed(goal)+1 print "Failed" end if end select read input$ wend print "Passed: ";passed(goal);" Failed: ";failed(goal) 'then report totals print "Total:" print "Passed: ";passed(0)+passed(1);" Failed: ";failed(0)+failed(1) print "-- Over! --"
end
'=========================================== '------------------------------------------- 'simple check by Henry function check1(var$) res=True if var$<>str$(val(var$)) then res=False check1 = res end function
'------------------------------------------- 'first try by timbim (adapted to return True or False) function check2(var$) res=True if checknum$(var$) = "Error" then res=False check2 = res end function
function checknum$(var$) var$ = trim$(var$) leng = len(var$) tot = 0 for x = 1 to leng if asc(mid$(var$, x, 1)) = 46 then point = point + 1 if asc(mid$(var$, x, 1)) > 57 or asc(mid$(var$, x, 1)) < 48 and asc(mid$(var$, x, 1)) <> 46 then err = 1 next if err = 1 or point > 1 then checknum$ = "Error" else checknum$ = "No error" end function '------------------------------------- 'suggestion by Rod function check3(var$) res = False num=val(var$) if num<> 0 and num-num=0 then res = True check3 = res end function '------------------------------------- 'tsh73 try 'credits for the idea goes to Jack W. Crenshaw 'in his tutorials "LET'S BUILD A COMPILER!" 'he used something like that for parsing expressions function IsNumber(input$) 'checks input$ for being valid number. Returns True if yes, False otherwise. IsNumber = 0 'check sign ns = eatUp(input$, "+-") if ns>1 then exit function 'with False 'now, digits n1 = eatUp(input$, "0123456789") 'could be decimal point nd = eatUp(input$, ".") if nd>1 then exit function 'then again, digits n2 = eatUp(input$, "0123456789") if n1+n2<1 then exit function 'now, exponent ne = eatUp(input$, "e") if ne<>0 then 'we have exponent if ne>1 then exit function 'check sign ns = eatUp(input$, "+-") if ns>1 then exit function 'now, digits n1 = eatUp(input$, "0123456789") if n1<1 then exit function end if
if input$="" then IsNumber = 1: exit function 'else we have leftovers - over with False end function
function eatUp(byRef input$, chars2eat$) 'trims all leading chars from input$ that match chars in chars2eat$ 'return count of trimmed characters count = 0 while len(input$)>0 if instr( chars2eat$, left$( input$,1))<>0 then input$ = mid$(input$,2) count = count +1 else exit while end if wend eatUp = count end function
|
|
hal9k
Junior Member
Posts: 87
|
Post by hal9k on Oct 11, 2022 18:31:22 GMT -5
Thanks guys. I was hoping somebody would tell me about the undocumented NUMERIC function in LB, but no such luck.
I'll incorporate your ideas and remember them for the future.
|
|
|
Post by Rod on Oct 12, 2022 2:47:17 GMT -5
If this is about user input you can of course control the actual input. You can with stylebits limit the input to numeric characters. You can with a combobox or series of comboboxes take complete control of the input. alycesrestaurant.com/lbpe/Stylebits%20-%20Textboxes.html shows how to limit input to numeric characters. This is kinda clunky but the user can't input anything other than the numbers I offer. WindowWidth = 800 WindowHeight = 400 'nomainwin a$(1) = "1" a$(2) = "2" a$(3) = "3" a$(4) = "4" a$(5) = "5" a$(6) = "6" a$(7) = "7" a$(8) = "8" a$(9) = "9" a$(0) = "0"
listbox #win.l1, a$(),dolist,10,10,45,140 listbox #win.l2, a$(),dolist,65,10,45,140 listbox #win.l3, a$(),dolist,120,10,45,140 button #win.b1,"Enter",[check],UL,185,10,50,20 open "Listbox Numeric Demo" for window as #win #win "trapclose [quit]" #win.l1 "selectindex 1" #win.l2 "selectindex 1" #win.l3 "selectindex 1" wait
[check] #win.l1 "selection? v1$" #win.l2 "selection? v2$" #win.l3 "selection? v3$" v=100*val(v1$)+10*val(v2$)+val(v3$) print v wait
[quit] close #win end
sub dolist h$ end sub
|
|
|
Post by Walt Decker on Oct 12, 2022 11:48:06 GMT -5
Mr. Pryor you might consider:
' Str0$ = "&hFF" A$ = FN.IsNumber$(Str0$, Yes) PRINT A$, Yes
Str1$ = "-123" A$ = FN.IsNumber$(Str1$, Yes) PRINT A$, Yes
Str2$ = "-123 abc" A$ = FN.IsNumber$(Str2$, Yes) PRINT A$, Yes Str3$ = "123abc" A$ = FN.IsNumber$(Str3$, Yes) PRINT A$, Yes
Str4$ = "123 abc" A$ = FN.IsNumber$(Str4$, Yes) PRINT A$, Yes
Str5$ = "-abc123" A$ = FN.IsNumber$(Str5$, Yes) PRINT A$, Yes
Str6$ = "-abc 123" A$ = FN.IsNumber$(Str6$, Yes) PRINT A$, Yes
Str7$ = "-4.123abc" A$ = FN.IsNumber$(Str7$, Yes) PRINT A$, Yes
Str8$ = "4.123abc" A$ = FN.IsNumber$(Str8$, Yes) PRINT A$, Yes
Str9$ = "-4.123 abc" A$ = FN.IsNumber$(Str9$, Yes) PRINT A$, Yes TRACE 2 Str10$ = "aebc-4.123" A$ = FN.IsNumber$(Str10$, Yes) PRINT A$, Yes
Str11$ = "253690.1578" A$ = FN.IsNumber$(Str11$, Yes) PRINT A$, Yes
Str11$ = "-4.1234698e12" A$ = FN.IsNumber$(Str11$, Yes) PRINT A$, Yes END FUNCTION FN.IsNumber$(NumStr$, BYREF True)
StrIn$ = "" Magic$ = "+-.0123456789E"
True = 1 LenIn = 0 LenNum = 0
StrIn$ = UPPER$(NumStr$) FOR I = 1 TO LEN(StrIn$) IF INSTR(Magic$, MID$(StrIn$, I, 1)) = 0 THEN True = 0 FN.IsNumber$ = NumStr$ EXIT FUNCTION END IF NEXT I
FN.IsNumber$ = NumStr$ END FUNCTION
'
You might want to put code in the function to handle hex numbers.
|
|
rnbw
New Member
Posts: 48
|
Post by rnbw on Oct 12, 2022 13:26:02 GMT -5
Is there a good way to do a numeric test? I couldn't find one, so I wrote this "brute force" function, but I suspect there is a better way.
Thanks!
FUNCTION FN.IsNumeric(String$) 'This function returns 1 if the string is numeric FN.IsNumeric = 1 'let's assume it's numeric FOR i = 1 TO LEN(String$) test = ASC(MID$(String$, i, 1)) IF test < 48 OR test > 57 THEN FN.IsNumeric = 0 EXIT FOR END IF NEXT i END FUNCTION Does this help. It is from Liberty Newsletter #121 June 2004
' FUNCTION NumberOnly$() - Bob Bromley - May 5, 2004
' Function is passed a string, discards any character that is not a number, a decimal point, ' or a minus sign (as long as it preceeds the number) and returns the result.
' NOTE: Numbers > 99,999,999.94 will return in exponential form. ' Numbers > 10,000,000 will round out to the nearest 10?.
nomainwin
WindowWidth = 300 : WindowHeight = 230 UpperLeftX = int((DisplayWidth - WindowWidth) / 2) UpperLeftY = int((DisplayHeight - WindowHeight) / 2) statictext #main.stat.1, "Enter something, (mix characters and numbers)", 35, 15, 290, 20 Stylebits #main.text.1, _ES_RIGHT, _WS_BORDER, 0, 0 textbox #main.text.1, 35, 40, 220, 25 statictext #main.stat.2, "The numeric result is", 90, 90, 100, 20 Stylebits #main.text.2, _ES_RIGHT, _WS_BORDER, 0, 0 textbox #main.text.2, 55, 115, 180, 25 button #main.butt.1, "Reset", [Reset], UL, 60, 160, 60, 25 button #main.butt.2, "Compute", [Compute], UL, 172, 160, 60, 25
open "Filtered Numeric Input" for window_nf as #main #main "trapclose [Quit]"
#main.text.1, "?-?1,2##-#,$$$-$,$34???5-6??7$(8)9.5#0"
#main.text.1 "!contents? amt$" ' An example, just to get started amt = NumberOnly(amt$) ' Make the conversion #main.text.2, trim$(using("############.##", amt)) ' Put the result in the lower textbox WAIT
[Compute] #main.text.1 "!contents? amt$" ' Get the user's input
' We must allow decimal points, but more than 1 will give us an incorrect return. ' So the first thing to do is count them, and stop here if there is more than 1. ' Use this for severe error-checking. ' ALSO NOTE: ' If you enter a minus sign anywhere other than the first character, it will be ' stripped and ignored. For example, enter 12-34 will result in 1234.00. ' -12-34 will result in -1234.00.
t = 0 for i = 1 to len(amt$) t$ = mid$(amt$, i, 1) : if t$ = "." then t = t + 1 if t > 1 then notice "Only 1 decimal point is allowed in the number! " : wait next
amt = NumberOnly(amt$) ' Make the conversion #main.text.2, trim$(using("############.##", amt)) ' Put the result in the lower textbox WAIT
[Reset] ' Blank both the textboxes #main.text.1, "" #main.text.2, "" #main.text.1 "!setfocus" ' Put the cursor in the upper textbox WAIT
[Quit] close #main END
FUNCTION NumberOnly(in$) ' Here is the meat of it! [Start] for i = 1 to len(in$) t$ = mid$(in$, i, 1) select case ' Do nothing if t$ is a numeral or a decimal point case asc(t$) = 46 OR (asc(t$) > 47) AND (asc(t$) < 58) ' A minus sign is ok, as long as it preceeds the numbers case asc(t$) = 45 AND i = 1 ' Discard any other character case else in$ = left$(in$, i - 1) + right$(in$, len(in$) - i) goto [Start] end select next NumberOnly = val(in$) END FUNCTION
|
|