[Source] Yet another IsNumeric() function [All OS]

Share your advanced PureBasic knowledge/code with the community.
User avatar
Mijikai
Addict
Addict
Posts: 1520
Joined: Sun Sep 11, 2016 2:17 pm

[Source] Yet another IsNumeric() function [All OS]

Post by Mijikai »

I didnt post anything for quite a while (bc. rl stuff) so here we go.
Maybe this is useful to someone, have fun :D

Edit:
Updated Code here: viewtopic.php?p=641661#p641661

Code (old - dont use!):

Code: Select all

EnableExplicit

;Yet another IsNumeric() function!
;Author: Mijikai

Procedure.b IsNumeric(*c.Character,d.i)
  Static.s p
  Static.Character *p
  Protected.Character *m
  Protected.i e,t,l
  p = "0123456789.-"
  *p = @p
  *m = *p
  If *c
    If *c\c <> 0 And *c\c <> '.'
      If *c\c = '-'
        *c + 2
        If *c\c <> 0 And *c\c <> '.'
          e = '-'
        EndIf
      Else
        e = '-'
      EndIf
      If e
        If d = 0
          e = '.'
        EndIf
        While *c\c <> 0
          While *m\c <> e
            If *m\c = *c\c
              If *m\c = '.'
                e = '.'
              EndIf
              t + 1
              Break
            EndIf
            *m + 2
          Wend  
          *m = *p
          *c + 2  
          l + 1
        Wend  
        *c - 2
        If t = l And *c\c <> '.'
          ProcedureReturn #True  
        EndIf
      EndIf
    EndIf
  EndIf
  ProcedureReturn #False
EndProcedure

Procedure.i main();Example
  Protected.s a,b
  a = "-10";<- numbers can be positive or negativ
  b = "1.0";<- optionally it can be a number with a dot '.'
  Debug IsNumeric(@a,0);<- just a number no other symbols expected 
  Debug IsNumeric(@b,1);<- set d to 1 if the number may contain a '.'
  ;Note:
  ;- No support for ',' instead of '.' (usually we use '.' for floats/doubles)
  ;- No support for notation ex. 'e-20'
EndProcedure

End main()
Last edited by Mijikai on Wed Jun 04, 2025 11:51 pm, edited 3 times in total.
User avatar
NicTheQuick
Addict
Addict
Posts: 1517
Joined: Sun Jun 22, 2003 7:43 pm
Location: Germany, Saarbrücken
Contact:

Re: [Source] Yet another IsNumeric() function [All OS]

Post by NicTheQuick »

Here some feedback:
  • Instead of using static variables you may just use a data section with the characters. Since labels are only valid in the local scope of a procedure this will not interfere with labels of the same name in other places.
  • Also the return type of `.b` is bad because it adds unnecessary low level type casting on modern 64 bit systems. Just use a `.i` there.
  • Please use meaningful variable names that can help future programmers understand your code better.
  • Instead of just adding 2 when iterating through the string, better use SizeOf(Character). I know that Purebasic nowadays only uses Unicode but this is also a helpful information for other coders to understand better what you are doing. It will not add any delay because the compiler replaces it with a 2 before compiling anyway.
  • The procedure will not recognize floating point values in the scientific format like 1.0e-5.
  • And last but not least: With some prototype magic you can get rid of the @ when calling the procedure.
Here is the code how I would write it, except for the meaningful variable names and the scientific format.

Code: Select all

EnableExplicit

;Yet another IsNumeric() function!
;Author: Mijikai

Procedure.i _IsNumeric(*c.Character, d.i)
	Debug *c
	Protected.Character *m
	Protected.i e, t, l
	*m = ?number_characters
	If *c
		If *c\c <> 0 And *c\c <> '.'
			If *c\c = '-'
				*c + SizeOf(Character)
				If *c\c <> 0 And *c\c <> '.'
					e = '-'
				EndIf
			Else
				e = '-'
			EndIf
			If e
				If d = 0
					e = '.'
				EndIf
				While *c\c <> 0
					While *m\c <> e
						If *m\c = *c\c
							If *m\c = '.'
								e = '.'
							EndIf
							t + 1
							Break
						EndIf
						*m + SizeOf(Character)
					Wend
					*m = ?number_characters
					*c + SizeOf(Character)
					l + 1
				Wend
				*c - SizeOf(Character)
				If t = l And *c\c <> '.'
					ProcedureReturn #True
				EndIf
			EndIf
		EndIf
	EndIf
	ProcedureReturn #False
	DataSection
		number_characters:
			Data.s "0123456789.-"
	EndDataSection
EndProcedure

; Use the prototype to always handover the string by reference
Prototype isNumericParams(text.p-Unicode, flags.i)

; Define the procedure in the global space with the right name
Global isNumeric.isNumericParams = @_IsNumeric()


Procedure.i main();Example
	Protected.s a,b
	a = "-10";<- numbers can be positive or negativ
	b = "1.0";<- optionally it can be a number with a dot '.'
	Debug @a
	Debug IsNumeric(a, 0);<- just a number no other symbols expected 
	Debug @b
	Debug IsNumeric(b, 1);<- set d to 1 if the number may contain a '.'
								;Note:
								;- No support for ',' instead of '.' (usually we use '.' for floats/doubles)
								;- No support for notation ex. 'e-20'
EndProcedure

End main()
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.
User avatar
Mijikai
Addict
Addict
Posts: 1520
Joined: Sun Sep 11, 2016 2:17 pm

Re: [Source] Yet another IsNumeric() function [All OS]

Post by Mijikai »

NicTheQuick wrote: Wed Jun 04, 2025 9:01 pm Here some feedback
Thanks for the feedback @NickTheQuick

Update 1

I hope the code is more readable now, i also added support for 1.0e-5 notation.
It still uses Static because its totally fine, i also did not add the Prototype for clarity.

Enjoy :D

Code:

Code: Select all

EnableExplicit

;Yet another IsNumeric() function!
;Update 1

Procedure.i IsNumeric(*text.Character,look_for_dot.i)
  Static.s pattern
  Static.Character *pattern
  Protected.Character *match
  Protected.i pattern_end
  Protected.i length_mached
  Protected.i length_text
  pattern = "0123456789.-"
  *pattern = @pattern
  *match = *pattern
  If *text
    If *text\c <> 0 And *text\c <> '.'
      If *text\c = '-'
        *text + SizeOf(Character)
        If *text\c <> 0 And *text\c <> '.'
          pattern_end = '-'
        EndIf
      Else
        pattern_end = '-'
      EndIf
      If pattern_end
        If look_for_dot = 0
          pattern_end = '.'
          While *text\c <> 0
            While *match\c <> pattern_end
              If *match\c = *text\c
                length_mached + 1
                Break
              EndIf
              *match + SizeOf(Character)
            Wend  
            *match = *pattern
            *text + SizeOf(Character) 
            length_text + 1
            If length_mached <> length_text
              ProcedureReturn #False
            EndIf
          Wend
        Else
          If *text\c = 'e' Or *text\c = 'E'
            ProcedureReturn #False
          EndIf
          While *text\c <> 0
            While *match\c <> pattern_end
              If *match\c = *text\c
                If *match\c = '.'
                  pattern_end = '.'
                EndIf
                length_mached + 1
                Break
              EndIf
              *match + SizeOf(Character)
            Wend
            If length_mached = length_text And look_for_dot <> 0
              If *text\c = 'e' Or *text\c = 'E' 
                *text + SizeOf(Character)
                If *text\c = '-' Or *text\c = '+'
                  *text - SizeOf(Character) << 1
                  If *text\c <> '.'
                    pattern_end = '.'
                    length_mached + 1
                    look_for_dot = 0
                  EndIf
                  *text + SizeOf(Character) << 1
                Else
                  *text - SizeOf(Character)
                EndIf
              EndIf
            EndIf
            *match = *pattern
            *text + SizeOf(Character)  
            length_text + 1
            If length_mached <> length_text
              ProcedureReturn #False
            EndIf
          Wend
        EndIf
        *text - SizeOf(Character)
        If *text\c <> '.' And *text\c <> '-'
          ProcedureReturn #True  
        EndIf
      EndIf
    EndIf
  EndIf
  ProcedureReturn #False
EndProcedure

Procedure.i main();Example
  Protected.s a,b
  a = "-10"                 ;<- numbers can be positiv or negativ
  b = "2.0E+10"             ;<- optionally it can be a number with a dot '.'
  Debug IsNumeric(@a,#False);<- set look_for_dot to #False if its just a number (no other symbols) 
  Debug IsNumeric(@b,#True) ;<- set look_for_dot to #True if the number may contain a dot '.'
EndProcedure

End main()
Post Reply