Page 1 of 1

Fast functions for numeric string value test

Posted: Sun Dec 31, 2023 1:06 pm
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

Re: Fast functions for numeric string value test

Posted: Sun Dec 31, 2023 1:30 pm
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.

Re: Fast functions for numeric string value test

Posted: Sun Dec 31, 2023 1:54 pm
by AZJIO
.b - useful in structure. You still occupy one "int" memory location.

Re: Fast functions for numeric string value test

Posted: Sun Dec 31, 2023 7:59 pm
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

Re: Fast functions for numeric string value test

Posted: Fri Jan 05, 2024 4:02 pm
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