Fast functions for numeric string value test

Share your advanced PureBasic knowledge/code with the community.
Oso
Enthusiast
Enthusiast
Posts: 595
Joined: Wed Jul 20, 2022 10:09 am

Fast functions for numeric string value test

Post by Oso »

Inspired by @highend's ongoing quest for the fastest possible extraction of trailing numbers from a string, https://www.purebasic.fr/english/viewto ... 54#p613654 I thought I'd use the opportunity to develop the code into numeric test functions. I seem to recall the question has been raised in the past but nevertheless I needed to write them myself, using only pointers.

Code: Select all

EnableExplicit

; **
; **  Numeric string value test routines, 3 forms
; **  ===========================================
; **
; **  (1) Strict test              IsNumberStrict()
; **  (2) Integer only test        IsNumberInt()
; **  (3) Other test               IsNumber()                 For reasons of need for compatibility with another environment, this
; **                                                          permits an input of only a '.' or '-' to be considered as numbers.
; **
; **



; **
; **  (1) Is number [strict check], returns true or false from string pointer
; **  Disallows only - or . and requires that - and . must be accompanied by at least a numeric digit
; **
Procedure.b IsNumberStrict(*StrPtr.Character)
  
  Protected num.b = #True                                               ; Number flag, assume true until otherwise
  Protected dec.b                                                       ; Decimal point counter
  Protected numfound.b                                                  ; Number subsequent to neg. sign found
  
  If *StrPtr\c = 45                                                     ; Neg. sign, if used must always be first char.
    *StrPtr + 2
  EndIf
    
  While *StrPtr\c                                                       ; Loop through until trailing zero
    Select *StrPtr\c                                                    ; Check non-zero
      Case 48 To 57                                                     ; Numeric range 0 to 9
        *StrPtr + 2                                                     ; Advance byte pos.
        numfound.b = #True                                              ; Number found
        
      Case 46                                                           ; Decimal point
        If dec.b                                                        ; Already seen decimal point, so
          num.b = #False                                                ; ... declare this as non-numeric
          Break
        EndIf
        
        *StrPtr + 2                                                     ; Advance byte pos.
        dec.b = #True                                                   ; Set flag, decimal found
        
      Default
        num.b = #False                                                  ; Non-numeric
        Break
    EndSelect
  Wend
  
  If numfound.b
    ProcedureReturn num.b                                               ; Return flag, true = number
  EndIf
  
EndProcedure

; **
; **  (2) Is number check [integer only, non-strict], returns true or false from string pointer
; **
Procedure.b IsNumberInt(*StrPtr.Character)
  
  Protected num.b = #True                                               ; Number flag, assume true until otherwise
  Protected numfound.b                                                  ; Number subsequent to neg. sign found
  
  If *StrPtr\c = 45                                                     ; Neg. sign, if used must always be first char.
    *StrPtr + 2
  EndIf
    
  While *StrPtr\c                                                       ; Loop through until trailing zero
    Select *StrPtr\c                                                    ; Check non-zero
      Case 48 To 57                                                     ; Numeric range 0 to 9
        *StrPtr + 2                                                     ; Advance byte pos.
        numfound.b = #True                                              ; Number found
        
      Default
        num.b = #False                                                  ; Non-numeric
        Break
    EndSelect
  Wend
  
  If numfound.b
    ProcedureReturn num.b                                               ; Return flag, true = number
  EndIf
  
EndProcedure

; **
; **  (3) Is number check [non-strict], returns true or false from string pointer, allows a string consisting of just - or . for
; **  reasons of compatibility
; **
Procedure.b IsNumber(*StrPtr.Character)
  
  Protected num.b = #True                                               ; Number flag, assume true until otherwise
  Protected dec.b                                                       ; Decimal point counter
  
  If *StrPtr\c = 45                                                     ; Neg. sign, if used must always be first char.
    *StrPtr + 2
  EndIf
    
  While *StrPtr\c                                                       ; Loop through until trailing zero
    Select *StrPtr\c                                                    ; Check non-zero
      Case 48 To 57                                                     ; Numeric range 0 to 9
        *StrPtr + 2                                                     ; Advance byte pos.
        
      Case 46                                                           ; Decimal point
        If dec.b                                                        ; Already seen decimal point, so
          num.b = #False                                                ; ... declare this as non-numeric
          Break
        EndIf
        
        *StrPtr + 2                                                     ; Advance byte pos.
        dec.b = #True                                                   ; Set flag, decimal found
        
      Default
        num.b = #False                                                  ; Non-numeric
        Break
    EndSelect
  Wend
  
  ProcedureReturn num.b                                                 ; Return flag, true = number
  
EndProcedure

OpenConsole()

Define ans.s

Repeat
  
  Print("Please enter a test value : ")
  ans.s = Input()
  
  If IsNumberStrict(@ans.s)                                             ; Use the functions by passing string by reference, this way
    PrintN("Yes, that is a valid number")
  Else
    PrintN("No, that is not a valid number")
  EndIf
  
ForEver
User avatar
mk-soft
Always Here
Always Here
Posts: 6224
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Fast functions for numeric string value test

Post by mk-soft »

Hi,
1. "-.1" is not number !?
2. "1e3" is number
3. Use Case '0' to '9' for better read code

A Boolean should not be defined as a byte. More ASM code is sometimes created.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
AZJIO
Addict
Addict
Posts: 2152
Joined: Sun May 14, 2017 1:48 am

Re: Fast functions for numeric string value test

Post by AZJIO »

.b - useful in structure. You still occupy one "int" memory location.
Oso
Enthusiast
Enthusiast
Posts: 595
Joined: Wed Jul 20, 2022 10:09 am

Re: Fast functions for numeric string value test

Post by Oso »

mk-soft wrote: Sun Dec 31, 2023 1:30 pm Hi,
1. "-.1" is not number !?
2. "1e3" is number
3. Use Case '0' to '9' for better read code

A Boolean should not be defined as a byte. More ASM code is sometimes created.
I wrote them to precisely match an existing end-user's commercial application that I'm replacing, so I'm constrained by its rules, and its flexibility too, but as a business app, those validations are normal. As a user input, -.1 is indeed allowed — it's taken as -10 Cents. 1e3 would not be allowed in a business application, so it's fine as it is. The intention is of course, just modify accordingly, to the extent that they are useful to those for whom they might be of benefit and if not, just do some other way that suits those needs. :D LOL

As it's now 2024 in this neck of the woods already, I wish all on here a very Happy New Year for the year ahead and thanks to all for another year of enjoyment with PB! All the best and a prosperous year year, best to Fred and team too :D
SMaag
Enthusiast
Enthusiast
Posts: 316
Joined: Sat Jan 14, 2023 6:55 pm
Location: Bavaria/Germany

Re: Fast functions for numeric string value test

Post by SMaag »

@Oso

For Numeric String Tests I started to develop a library at end of 2022!
It is still under development because it is part of a bigger project.
Maybe we can joyn our forces and make it better.

look at
https://github.com/Maagic7/PureBasicFra ... Numeric.pb
Post Reply