QB64.org Forum

Active Forums => QB64 Discussion => Topic started by: xra7en on December 21, 2018, 10:28:42 am

Title: Does a Is Number function exist in QB64?
Post by: xra7en on December 21, 2018, 10:28:42 am
So I needed something like this (sloppy I know but works for now, I'll rerturn to it later to clean up, unless one already exists)
Code: QB64: [Select]
  1. FUNCTION IS_NUMBER (NUM AS STRING) ' returns 1 if string is an integer, 0 if not
  2.     DIM TEMPNUMBER AS INTEGER
  3.     DIM HAYSTACK AS STRING
  4.     DIM I, j AS INTEGER
  5.  
  6.     NUM = UCASE$(NUM)
  7.     '// simplified number check
  8.     '// Useful for getting a user input where one answer needs to be determined if
  9.     '// if it a string answer or a numeric input
  10.     HAYSTACK = "ABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()_+=-,?/|<>][{}:;'" + CHR$(32) + CHR$(34)
  11.     '// If the NUM string has any of the above characters it is not a numb
  12.     FOR I = 1 TO LEN(NUM)
  13.         FOR j = 1 TO LEN(HAYSTACK)
  14.             IF INSTR(MID$(HAYSTACK, j, I), MID$(NUM, I, 1)) > 0 THEN
  15.                 IS_NUMBER = 0
  16.                 EXIT FUNCTION
  17.             END IF
  18.         NEXT
  19.     NEXT
  20.  
  21.     IS_NUMBER = 1
  22.  

Just checks a string input to see if it is a number or not, 1 = yes 0 = no simple

Does QB64 have something like this?
Title: Re: Does a Is Number function exist in QB64?
Post by: FellippeHeitor on December 21, 2018, 10:38:43 am
Not natively.
Title: Re: Does a Is Number function exist in QB64?
Post by: Cobalt on December 21, 2018, 10:46:43 am
so you want to check if the string is only a number or if it contains a number?

'Checking that text is all numbers
Function IS_NUMBER(TXT$)
 for I%= 1 to len(TXT$)
  test$=mid$(TXT$, I%,1)
  if asc(test$)>=48 and asc(test$)<=57 then Good%%=-1 else Good%%=0
  if NOT Good%% then I%=LEN(TXT$)+1
 next I%
 IS_NUMBER=Good%%
end function

'Checking if it contains Numbers
Function HAS_NUMBER(TXT$)
 for I%= 1 to len(TXT$)
  test$=mid$(TXT$, I%,1)
  if asc(test$)>=48 and asc(test$)<=57 then Good%%=-1 else Good%%=0
  if Good%% then I%=LEN(TXT$)+1
 next I%
 HAS_NUMBER=Good%%
end function

its pretty simple, but yeah as Fellippe says there is no built in function for that.
now if you wanted to allow for decimal points '.' you would simply add that check to the IF THEN. (ASC(46))
Title: Re: Does a Is Number function exist in QB64?
Post by: FellippeHeitor on December 21, 2018, 10:49:27 am
You could probably check if LTRIM$(RTRIM$(STR$(VAL(num$)))) = LTRIM$(RTRIM$(num$)).
Title: Re: Does a Is Number function exist in QB64?
Post by: xra7en on December 21, 2018, 11:41:46 am
You could probably check if LTRIM$(RTRIM$(STR$(VAL(num$)))) = LTRIM$(RTRIM$(num$)).

OO that is nice...
I whipped this up at 3am after my cats woke me up LOL

for some reason , many years ago, i thought there was a one liner like that.. let me try that one. makes more sense.
I love writing text games, and sometimes you have to make an option fo 1 - 100 or R-eturn, Q-uit or a array of other string answers mixed with numeric within the same input. PHP has one like this


EDIT:

KISS IS GOOD! thanks.

Title: Re: Does a Is Number function exist in QB64?
Post by: xra7en on December 21, 2018, 11:43:20 am
so you want to check if the string is only a number or if it contains a number?

'Checking that text is all numbers
Function IS_NUMBER(TXT$)
 for I%= 1 to len(TXT$)
  test$=mid$(TXT$, I%,1)
  if asc(test$)>=48 and asc(test$)<=57 then Good%%=-1 else Good%%=0
  if NOT Good%% then I%=LEN(TXT$)+1
 next I%
 IS_NUMBER=Good%%
end function

'Checking if it contains Numbers
Function HAS_NUMBER(TXT$)
 for I%= 1 to len(TXT$)
  test$=mid$(TXT$, I%,1)
  if asc(test$)>=48 and asc(test$)<=57 then Good%%=-1 else Good%%=0
  if Good%% then I%=LEN(TXT$)+1
 next I%
 HAS_NUMBER=Good%%
end function

its pretty simple, but yeah as Fellippe says there is no built in function for that.
now if you wanted to allow for decimal points '.' you would simply add that check to the IF THEN. (ASC(46))

very nice.. let me tear this apart and check it out as well. the decimal is what I added in mine. While most users are normal, my HAYSTACK does not check for ALL googy stuff players might try to input (games are more prone to people enter strings to find an exploit that regular aps) LOL
Title: Re: Does a Is Number function exist in QB64?
Post by: SMcNeill on December 21, 2018, 11:51:08 am
FUNCTION IsNum (text$)
    a$ = _TRIM$(text$)
    b$ = _TRIM$(STR$(VAL(text$)))
    IF a$ = b$ THEN IsNum = 1
END FUNCTION

Will the above work for your needs?
Title: Re: Does a Is Number function exist in QB64?
Post by: bplus on December 21, 2018, 12:44:23 pm
Two comments:

1. in OP code, you comment the function to check for integer that is something like:
Code: QB64: [Select]
  1. if number = int(number) then isInteger = true

2. For most generic IsNumber function watch out for letters used for exponents in float types, E or D (I don't usually deal with numbers that big or small). Might get around this with Fellippe and Steve's examples but check.
Title: Re: Does a Is Number function exist in QB64?
Post by: xra7en on December 21, 2018, 01:28:30 pm
Two comments:

1. in OP code, you comment the function to check for integer that is something like:
Code: QB64: [Select]
  1. if number = int(number) then isInteger = true

2. For most generic IsNumber function watch out for letters used for exponents in float types, E or D (I don't usually deal with numbers that big or small). Might get around this with Fellippe and Steve's examples but check.

I don't see the
Code: QB64: [Select]
  1. if number = int(number) then isInteger = true
However VERY VERY good point - Unless I am writing some "clicker"/"idle" game I do not work with numbers quite that high, however, to cover all bases, that is something to check.
Title: Re: Does a Is Number function exist in QB64?
Post by: FellippeHeitor on December 21, 2018, 01:33:33 pm
FUNCTION IsNum (text$)
    a$ = _TRIM$(text$)
    b$ = _TRIM$(STR$(VAL(text$)))
    IF a$ = b$ THEN IsNum = 1
END FUNCTION

Will the above work for your needs?

My point exactly.
Title: Re: Does a Is Number function exist in QB64?
Post by: xra7en on December 21, 2018, 03:12:46 pm
FUNCTION IsNum (text$)
    a$ = _TRIM$(text$)
    b$ = _TRIM$(STR$(VAL(text$)))
    IF a$ = b$ THEN IsNum = 1
END FUNCTION

Will the above work for your needs?

Yes, and simpler :-)
Title: Re: Does a Is Number function exist in QB64?
Post by: FellippeHeitor on December 21, 2018, 03:14:00 pm
Friendly reminder that _TRIM$ hasn't made it into the stable build and is available only if you're beta testing the dev build.
Title: Re: Does a Is Number function exist in QB64?
Post by: xra7en on December 21, 2018, 06:12:19 pm
Friendly reminder that _TRIM$ hasn't made it into the stable build and is available only if you're beta testing the dev build.

thanks for the update...
no rush here! QB64 is way flexible enough to adjust for it :-)

Title: Re: Does a Is Number function exist in QB64?
Post by: Cobalt on December 22, 2018, 12:00:43 am

very nice.. let me tear this apart and check it out as well. the decimal is what I added in mine. While most users are normal, my HAYSTACK does not check for ALL googy stuff players might try to input (games are more prone to people enter strings to find an exploit that regular aps) LOL

that is the thing about games as opposed to applications, you have to deal with a lot more checking.
Title: Re: Does a Is Number function exist in QB64?
Post by: MWheatley on December 29, 2018, 10:57:06 am
One thing that I think has been overlooked here is to test for negative numbers, in other words, look for a minus sign, as well as a decimal point.

I've used this code for the last 30 years or so -- it's a bit clumsy, but is an easy bit of fire-and-forget code that gets copied into just about every program that I write.  (Which isn't many, these days.)

In other words, you want to test for ASCII 45 and ASCII 46, but want to eliminate ASCII 47 ( the "/" character).

The jump to "notanumber" in the code below basically links to a bit of code that first erases the invalid text, and then beeps.

Code: QB64: [Select]
  1. FOR i = 1 TO LEN(text$)
  2. IF ASC(MID$(text$, i, 1)) < 45 OR ASC(MID$(text$, i, 1)) >= 58 GOTO notanumber
  3. ' It's not a number, minus sign, / or . character, so goto notanumber
  4. IF ASC(MID$(text$, i, 1)) = 47 GOTO notanumber
  5. REM: it's a / character, so goto notanumber
  6.  
Malcolm
Title: Re: Does a Is Number function exist in QB64?
Post by: xra7en on December 29, 2018, 10:41:34 pm
Like it!
I'll check it out.. and put it in my bag of utils.bi :-)
Title: Re: Does a Is Number function exist in QB64?
Post by: xra7en on December 29, 2018, 11:16:11 pm
here is what I did with your code... what do you think?


Code: QB64: [Select]
  1. FUNCTION IS_NUMBER (text AS STRING) ' returns 1 if string is an integer, 0 if not
  2.     IS_NUMBER = 1
  3.     FOR i = 1 TO LEN(text$)
  4.         IF ASC(MID$(text$, i, 1)) < 45 OR ASC(MID$(text$, i, 1)) >= 58 THEN IS_NUMBER = 0
  5.         ' It's not a number, minus sign, / or . character, so goto notanumber
  6.         IF ASC(MID$(text$, i, 1)) = 47 THEN IS_NUMBER = 0
  7.         ' it's a / character, so goto notanumber
  8.     NEXT i
  9.  
Title: Re: Does a Is Number function exist in QB64?
Post by: MWheatley on December 30, 2018, 09:40:47 am
That looks fine -- glad to have helped.  (Nice to give something back, for a change!)

As I say, it's a bit of code that has worked for me for many, many years.

Malcolm
Title: Re: Does a Is Number function exist in QB64?
Post by: MWheatley on January 01, 2019, 11:24:30 am
here is what I did with your code... what do you think?


Code: QB64: [Select]
  1. FUNCTION IS_NUMBER (text AS STRING) ' returns 1 if string is an integer, 0 if not
  2.     IS_NUMBER = 1
  3.     FOR i = 1 TO LEN(text$)
  4.         IF ASC(MID$(text$, i, 1)) < 45 OR ASC(MID$(text$, i, 1)) >= 58 THEN IS_NUMBER = 0
  5.         ' It's not a number, minus sign, / or . character, so goto notanumber
  6.         IF ASC(MID$(text$, i, 1)) = 47 THEN IS_NUMBER = 0
  7.         ' it's a / character, so goto notanumber
  8.     NEXT i
  9.  

Out of interest, I'd be interested in seeing a piece of code that used this function.  As I've just typed elsewhere, I almost never use functions, and would appreciate seeing an example using a bit of code I know and understand.

(If you're wondering why, it's chiefly that early BASICs made functions difficult (to me, anyway), and by the time QB45 came along, I'd got out of the habit.  Plus, the QB45 IDE doesn't exactly make the experience all that user-friendly, either.)

Malcolm

Title: Re: Does a Is Number function exist in QB64?
Post by: bplus on January 01, 2019, 12:29:03 pm
Hi Malcohm,

Here is a quick demo showing the use of the function:
Code: QB64: [Select]
  1.     PRINT: INPUT "Please enter a number or not to test the IS_NUMBER function > ", test$
  2.  
  3.    'the next line uses the function
  4.     IF IS_NUMBER(test$) = 1 THEN PRINT "Is a number" ELSE PRINT " NOT a number."
  5.  
  6.     INPUT "Test function again? y for yes ", again$
  7. LOOP UNTIL again$ <> "y"
  8.  
  9. FUNCTION IS_NUMBER (text AS STRING) ' returns 1 if string is an integer, 0 if not
  10.     IS_NUMBER = 1
  11.     FOR i = 1 TO LEN(text$)
  12.         IF ASC(MID$(text$, i, 1)) < 45 OR ASC(MID$(text$, i, 1)) >= 58 THEN IS_NUMBER = 0
  13.         ' It's not a number, minus sign, / or . character, so goto notanumber
  14.         IF ASC(MID$(text$, i, 1)) = 47 THEN IS_NUMBER = 0
  15.         ' it's a / character, so goto notanumber
  16.     NEXT i
  17.  

BTW the function fails for numbers like
Code: QB64: [Select]
  1. n = 23E29

Also thinks 23-. is a number!
Title: Re: Does a Is Number function exist in QB64?
Post by: SMcNeill on January 01, 2019, 04:26:25 pm
here is what I did with your code... what do you think?

Out of interest, I'd be interested in seeing a piece of code that used this function.  As I've just typed elsewhere, I almost never use functions, and would appreciate seeing an example using a bit of code I know and understand.

(If you're wondering why, it's chiefly that early BASICs made functions difficult (to me, anyway), and by the time QB45 came along, I'd got out of the habit.  Plus, the QB45 IDE doesn't exactly make the experience all that user-friendly, either.)

Malcolm

You use FUNCTIONs all the time in your code.  Your original code is chock full of them...

FOR i = 1 TO LEN(text$)
IF ASC(MID$(text$, i, 1)) < 45 OR ASC(MID$(text$, i, 1)) >= 58 GOTO notanumber

Of the above, we have 2 lines of code and 3 functions:  LEN(), ASC(), MID$()

At its base, all a FUNCTION is, is a routine which gives you a return value.  A SUB on the other hand, doesn’t.

CLS — this is a SUB.
PRINT — this is a SUB.
ASC() — This returns a value, so is a FUNCTION.
CHR$() — Function.
SIN(), COS(), TAN() — all FUNCTIONs.

If it’s a routine which gives you a return value, which you can use from the right side of an equal sign, it’s a FUNCTION:

X = whatever(), and whatever() is a FUNCTION.

IF your command is a stand-alone procedure which can’t go to the right side of an equal sign, it’s a SUB:

X = PRINT “Hello World” — for example.



You’ve used functions all the time in your code.  You just haven’t been creating any CUSTOM functions of your own, from the way your post sounds.  When you do, you just end up using them like you have been, with all usual rules and syntax applying.
Title: Re: Does a Is Number function exist in QB64?
Post by: FellippeHeitor on January 05, 2019, 03:38:16 pm
This isnumber() function is present in source/qb64.bas and I've adapted it recently to recognise scientific notation as well:

Code: QB64: [Select]
  1. FUNCTION isnumber (a$)
  2.     IF LEN(a$) = 0 THEN EXIT FUNCTION
  3.     FOR i = 1 TO LEN(a$)
  4.         a = ASC(MID$(a$, i, 1))
  5.         IF a = 45 THEN
  6.             IF (i = 1 AND LEN(a$) > 1) OR (i > 1 AND (d = i - 1 OR E = i - 1)) THEN _CONTINUE
  7.             EXIT FUNCTION
  8.         END IF
  9.         IF a = 46 THEN
  10.             IF dp = 1 THEN EXIT FUNCTION
  11.             dp = 1
  12.             _CONTINUE
  13.         END IF
  14.         IF a = 100 OR a = 68 THEN 'D
  15.             IF d > 1 OR E > 1 THEN EXIT FUNCTION
  16.             d = i
  17.             _CONTINUE
  18.         END IF
  19.         IF a = 101 OR a = 69 THEN 'E
  20.             IF d > 0 OR E > 1 THEN EXIT FUNCTION
  21.             E = i
  22.             _CONTINUE
  23.         END IF
  24.         IF a = 43 THEN '+
  25.             IF d = i - 1 OR E = i - 1 THEN _CONTINUE
  26.             EXIT FUNCTION
  27.         END IF
  28.  
  29.         IF a >= 48 AND a <= 57 THEN _CONTINUE
  30.         EXIT FUNCTION
  31.     NEXT
  32.     isnumber = 1
Title: Re: Does a Is Number function exist in QB64?
Post by: SMcNeill on January 05, 2019, 08:08:32 pm
I just wanted to waste some time on something this evening, so I decided to toss my hat into the ring and over-engineer a number checker...  Here's what I came up with; feel free to test it and point out any glitches which I produced.

Code: QB64: [Select]
  1. DIM test(10) AS STRING
  2. DATA "123a.3","-123.456","--234","1.23E15","123","dogfood","678.965","54678","-987134","23.4.5"
  3.  
  4. FOR i = 1 TO 10
  5.     READ test(i)
  6.  
  7. FOR i = 1 TO 10
  8.     PRINT "TEST #"; i; ": "; test(i) + " "
  9.     result = NumberType(test(i))
  10.     IF result = 0 THEN PRINT "INVALID: "; NumErr$
  11.     IF result AND 1 THEN PRINT "Valid Unsigned Byte.  ";
  12.     IF result AND 2 THEN PRINT "Valid Unsigned Integer.  ";
  13.     IF result AND 4 THEN PRINT "Valid Unsigned Long.  ";
  14.     IF result AND 8 THEN PRINT "Valid Unsigned Integer64.  ";
  15.     IF result AND 16 THEN PRINT "Valid Signed Byte.  ";
  16.     IF result AND 32 THEN PRINT "Valid Signed Integer.  ";
  17.     IF result AND 64 THEN PRINT "Valid Signed Long.  ";
  18.     IF result AND 128 THEN PRINT "Valid Signed Integer64.  ";
  19.     IF result AND 256 THEN PRINT "Valid Single.  ";
  20.     IF result AND 512 THEN PRINT "Valid Double.  ";
  21.     IF result AND 1024 THEN PRINT "Valid Float.  ";
  22.     PRINT
  23.     PRINT
  24.     SLEEP
  25.  
  26.  
  27. FUNCTION NumberType~% (text$)
  28.     SHARED NumErr$
  29.     temp$ = UCASE$(_TRIM$(text$))
  30.     NumErr$ = "" 'reset the error message
  31.  
  32.     'First check for negative values; flag for invalid cases of multiple negation.
  33.     IF MID$(temp$, 1, 1) = "-" THEN negative = -1
  34.     FOR i = 1 TO LEN(temp$)
  35.         IF MID$(temp$, i, 1) = "-" THEN minus = minus + 1
  36.         IF MID$(temp$, i, 1) = "." THEN period = period + 1 'Go ahead and check for multiple periods while we're at it.
  37.     NEXT
  38.     IF minus > 1 THEN NumErr$ = _TRIM$(STR$(minus)) + " negative signs (-) encountered, rendering string not to be a valid number.  "
  39.     IF negative THEN temp$ = MID$(temp$, 2) 'strip off the minus
  40.  
  41.     'Check for integer values if no period is present
  42.     IF period = 0 THEN 'we don't have to worry about any sort of float values, so check for just numbers
  43.         FOR i = 1 TO LEN(temp$)
  44.             t$ = MID$(temp$, i, 1)
  45.             IF t$ < "0" OR t$ > "9" THEN NumErr$ = NumErr$ + "Invalid Character (" + t$ + ") encountered.  "
  46.         NEXT
  47.     ELSEIF period = 1 THEN 'We have a single period; it may be a valid SINGLE/DOUBLE/FLOAT
  48.         FOR i = 1 TO LEN(temp$)
  49.             t$ = MID$(temp$, i, 1)
  50.             IF t$ = "E" OR t$ > "D" THEN Exponent = Exponent + 1
  51.             IF t$ < "0" OR t$ > "9" THEN
  52.                 IF (t$ = "E" OR t$ = "D") AND Exponent > 1 THEN NumErr$ = NumErr$ + "Invalid Character (" + t$ + ") encountered.  "
  53.                 IF t$ <> "E" AND t$ <> "D" AND t$ <> "." THEN NumErr$ = NumErr$ + "Invalid Character (" + t$ + ") encountered.  "
  54.             END IF
  55.         NEXT
  56.         IF Exponent > 1 THEN
  57.             NumErr$ = NumErr$ + _TRIM$(STR$(Exponent)) + " Exponential Characters, rendering REAL values impossible.  "
  58.         ELSEIF Exponent = 1 THEN
  59.             IF MID$(temp$, 2, 1) <> "." THEN NumErr$ = NumErr$ + "Rejected for non-standard numeric value; too many digits before Exponnential Character."
  60.         END IF
  61.     ELSE 'We have too many periods to be a valid number
  62.         NumErr$ = NumErr$ + _TRIM$(STR$(period)) + " periods (.) encountered, rendering string not to be a valid number.  "
  63.     END IF
  64.  
  65.     IF NumErr$ = "" THEN
  66.         'It's a valid number
  67.         t## = VAL(temp$)
  68.         IF period = 0 THEN 'integer
  69.             IF t## >= -128 AND t## <= 127 THEN NumberType = NumberType OR 16 'signed byte
  70.             IF t## >= -32768 AND t## <= 32767 THEN NumberType = NumberType OR 32 'signed integer
  71.             IF t## >= -2147483648 AND t## <= 2147483647 THEN NumberType = NumberType OR 64 'signed long
  72.             IF t## >= -9223372036854775808 AND t## <= 9223372036854775807 THEN NumberType = NumberType OR 128 'signed integer64
  73.             IF negative = 0 THEN 'unsigned
  74.                 IF t## <= 255 THEN NumberType = NumberType OR 1 'unsigned byte
  75.                 IF t## <= 65535 THEN NumberType = NumberType OR 2 'unsigned integer
  76.                 IF t## <= 4294967295 THEN NumberType = NumberType OR 4 'unsigned long
  77.                 IF t## <= 18446744073709551615 THEN NumberType = NumberType OR 8 'unsigned integer64
  78.             END IF
  79.         END IF
  80.         IF t## >= -2.802597E-45 AND t## <= 3.402823E+38 THEN NumberType = NumberType OR 256 'single
  81.         IF t## >= -4.490656458412465E-324 AND t## <= 1.797693134862310E+308 THEN NumberType = NumberType OR 512 'double
  82.         IF t## >= -1.18E-4932 AND t## <= 1.18E+4932 THEN NumberType = NumberType OR 1024 'float
  83.     END IF
  84.  

Singles/doubles/floats might be a little glitchy, as I don't usually find myself using scientific notation for ANYTHING, really...  I may have some of the basic rules of the format wrong, and if so, I'll go in and adjust them later and correct them.

For example, is 1E15 a valid number?  Or does it need to be 1.0E15 with that decimal in there?   Currently, it flags as INVALID, as I was thinking the decimal was required -- but I freely admit, I may be wrong guessing that...   It happens sometimes.  :P
Title: Re: Does a Is Number function exist in QB64?
Post by: FellippeHeitor on January 05, 2019, 11:28:24 pm
For example, is 1E15 a valid number?

Google says it is https://www.mathsisfun.com/numbers/scientific-notation.html
Title: Re: Does a Is Number function exist in QB64?
Post by: luke on January 06, 2019, 12:17:50 am
QB64 unfortunately doesn't have any functions for using regular expressions, but here's one that'll match numbers:
Code: QB64: [Select]
  1. /^-?(&h[\da-f]+|&o[0-7]+|&b[01]+|(\d+\.?\d*|\.?\d+)([ed][-+]?\d*)?)$/i

This allows for &H/&O/&B numbers, regular integers, floating point numbers, and even decimals with leading/trailing decimal points like ".23" or "23." which are valid in QB64.

You can play with it here: https://regex101.com/r/2EP3G2/1