Announcement

Collapse
No announcement yet.

Best Way To Test if a String is Numeric?

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Best Way To Test if a String is Numeric?

    What is the best way to test if a string is convertible to a LONG?

    Something like this? Or is there a better way?

    Code:
    LOCAL x AS LONG
    LOCAL s AS STRING
    
    s = "Not Happening"
    
    ON ERROR RESUME NEXT
    x = CLNG(s)
    IF ERR THEN
        PRINT "Not Convertible!"
    ELSE
        PRINT "Convertible"
    END IF
    Secret News | Mercury | Vaccines | Geoengineering | Utilities Made with PowerBasic

  • #2
    Code:
    If Len(SomeString$) = Len(Retain$(SomeString$, Any "0123456789")) Then ? "String is numeric!"
    Scott Slater
    Summit Computer Networks, Inc.
    www.summitcn.com

    Comment


    • #3
      Russell --

      Is the number allowed to be negative?

      -- Eric
      "Not my circus, not my monkeys."

      Comment


      • #4
        Also, are you going to allow only decimal or other number bases also?

        What sort of invalid data do you expect to receive? Assuming decimal, a string length >9 has no chance. If you expect a lot of too-long strings, a IF LEN(whatever) > 9 THEN ITERATE might be in order. Only if that test passes do you test further. But if you are using STRING*8, you know the focus should be on invalid characters (and maybe also empty strings).
        Erich Schulman (KT4VOL/KTN4CA)
        Go Big Orange

        Comment


        • #5
          Code:
          IF VAL(Format$(number)) = Number Then 
            I guess it can be converted OK
          Gotta be something similar to test a string...
          Code:
          IF FORMAT$(VAL(String)) = LTRIM$(string) then 
             I guess the string is convertible.
          That will work for decimal character strings; other bases or formats (eg scientific notiation) will require more manipulation.
          Last edited by Michael Mattias; 11 Mar 2010, 10:13 AM.
          Michael Mattias
          Tal Systems (retired)
          Port Washington WI USA
          [email protected]
          http://www.talsystems.com

          Comment


          • #6
            Code:
            If Len(SomeString$) = Len(Retain$(SomeString$, Any "0123456789")) Then _ 
                ? "String is numeric!"
            ==>
            Code:
            IF VERIFY (somestring, "0123456789") = 0 THEN _ 
               ? "String consists only of the decimal digits"
            I think that's the same test as the LEN/RETAIN$ thing. (which is NOT the same as the VAL() test, as VAL will both LTRIM the string and use all characters up the the first non-qualifying character).

            MCM
            Michael Mattias
            Tal Systems (retired)
            Port Washington WI USA
            [email protected]
            http://www.talsystems.com

            Comment


            • #7
              BTW....
              Code:
              ON ERROR RESUME NEXT 
               ...
               IF ERR  THEN
              ...you probably need not even bother looking for a test involving the system ERR variable. AFAIK ERR is not set on any numeric function or operation.
              Michael Mattias
              Tal Systems (retired)
              Port Washington WI USA
              [email protected]
              http://www.talsystems.com

              Comment


              • #8
                Code:
                #INCLUDE "WIN32API.INC"
                 
                Function PbMain()
                 Local sTest$, x&
                 
                  For x = 1 To Datacount
                    If VERIFY(Read$(x), "-0123456789") Then
                      sTest = sTest + " Non-Integer" + $Tab + Read$(x) + $CR
                    Else
                      If (Val(Read$(x)) >= -2147483648) AND (Val(Read$(x)) <= 2147483647) Then
                        sTest = sTest + " Long Integer" + $Tab + Read$(x) + $CR
                      End If
                   End If
                 Next
                 
                 MESSAGEBOX 0, ""+sTest, "String Test", %MB_ICONMASK
                 
                  DATA  -123, 1234a, 67891234, " ", cat
                 
                End Function
                Last edited by Dave Biggs; 11 Mar 2010, 11:22 AM. Reason: Reformat for PBCC
                Rgds, Dave

                Comment


                • #9
                  I have not run your code but that is a really nice technique you used for your test program, using DATA statements like that to allow testing of all kinds of input.
                  Michael Mattias
                  Tal Systems (retired)
                  Port Washington WI USA
                  [email protected]
                  http://www.talsystems.com

                  Comment


                  • #10
                    Another possible method for specifically testing to see if it is inside the range of a LONG:

                    Code:
                    #COMPILE EXE
                    #DIM ALL
                    
                    %TRUE = 1
                    %FALSE = 0
                    
                    DECLARE FUNCTION CanBeLongInt(inBuf AS STRING) AS LONG
                    
                    FUNCTION PBMAIN () AS LONG
                    
                        ? CanBeLongInt("1.1")
                        ? CanBeLongInt("11")
                        ? CanBeLongInt("11004")
                        ? CanBeLongInt("1234231004")
                        ? CanBeLongInt("4231004")
                        ? CanBeLongInt("4465754523")
                        ? CanBeLongInt("-3555231004")
                        ? CanBeLongInt("77.65")
                        ? CanBeLongInt("ABCD")
                    
                        WAITKEY$
                    
                    END FUNCTION
                    
                    FUNCTION CanBeLongInt(inBuf AS STRING) AS LONG
                    
                        LOCAL tmp   AS STRING
                        LOCAL tmp2  AS STRING
                        LOCAL lRet  AS LONG
                        
                        tmp = inBuf
                        tmp2 = RETAIN$(tmp, ANY "-0123456789")
                        IF tmp2 <> tmp THEN
                            lRet = %FALSE
                            GOTO ExitFunc
                        END IF
                        
                        IF VAL(tmp) < -2147483648& THEN
                            lRet = %FALSE
                            GOTO ExitFunc
                        END IF
                        
                        IF VAL(tmp) > 2147483647& THEN
                            lRet = %FALSE
                            GOTO ExitFunc
                        END IF
                        
                        lRet = %TRUE
                        
                    ExitFunc:
                    
                        FUNCTION = lRet
                    
                    END FUNCTION
                    Adam Drake
                    Drake Software

                    Comment


                    • #11
                      >FUNCTION CanBeLongInt(inBuf AS STRING) AS LONG

                      I would have written this thing as a procedure to start.

                      Now, put your DATA statements into PBMAIN and you can test with four lines of code...
                      Code:
                      FUNCTION PBMAIN() AS LONG
                        FOR Z = 1 TO DATACOUNT 
                             S = READ$(Z)
                             ? USING$(" Loop # Raw string '&'  CabBeLongInt #", Z, S, CanBeLongInt(s)) 
                        NEXT 
                      
                      DATA .......
                      END FUNCTION
                      MCM
                      Michael Mattias
                      Tal Systems (retired)
                      Port Washington WI USA
                      [email protected]
                      http://www.talsystems.com

                      Comment


                      • #12
                        I've been using these functions for more than a few years. They're ASM, and pretty dang fast. (No benchmarks to display; I just looked at my watch. )

                        I found IsNumeric in the source code forum, I think. I modified it to write the rest to meet various needs as they have cropped up.

                        Below is the code for:
                        IsNumeric
                        IsNumericEX
                        IsAlpha
                        IsAlphaNumeric
                        IsCapAlpha
                        IsZIP


                        Code:
                        '===============================================================================================
                        '// Returns True  if a string is numeric (0-9)
                        FUNCTION IsNumeric(s AS STRING) AS LONG
                        #REGISTER NONE
                        LOCAL sPtr&, sLen&
                           ON ERROR RESUME NEXT
                           sPtr = STRPTR(s)
                           sLen& = STRPTR(s) + LEN(s)
                           ! mov eax, sPtr ;ptr to string
                           ! mov ecx, sLen ;addr: end of string
                        StartLoop531:
                           ! mov bl, [eax]
                           ! cmp bl, 48
                           ! jl  NotNumeric531  ; < 48? Not numeric
                           ! cmp bl, 57
                           ! jg  NotNumeric531  ; > 57? Not numeric
                           ! inc eax
                           ! cmp eax, ecx
                           ! je  EndLoop531
                           ! jmp StartLoop531
                        NotNumeric531:
                           FUNCTION = %False
                           EXIT FUNCTION
                        EndLoop531:
                           FUNCTION = %True
                        END FUNCTION
                        '===============================================================================================
                        '// Returns 1 if a string is numeric (0 through 9, and the Plus (+), Minus(-), and  Decimal (.)
                        FUNCTION IsNumericEX(s AS STRING) AS LONG
                        #REGISTER NONE
                        LOCAL sPtr&, sLen&
                           ON ERROR RESUME NEXT
                           sPtr = STRPTR(s)
                           sLen& = STRPTR(s) + LEN(s)
                           ! mov eax, sPtr ;ptr to string
                           ! mov ecx, sLen ;addr: end of string
                        StartLoop533:
                           ! mov bl, [eax]
                           ! cmp bl, 43
                           ! jl  NotNumeric533   ; lower than minus
                           ! cmp bl, 46
                           ! jle OKgoon533   ;  is decimal, or comma, or plus, or minus
                           ! cmp bl, 48
                           ! jl  NotNumeric533  ; < 48? Not numeric
                           ! cmp bl, 57
                           ! jg  NotNumeric533  ; > 57? Not numeric
                        OKgoon533:
                           ! inc eax
                           ! cmp eax, ecx
                           ! je  EndLoop533
                           ! jmp StartLoop533
                        NotNumeric533:
                           FUNCTION = %False
                           EXIT FUNCTION
                        EndLoop533:
                           FUNCTION = %True
                        END FUNCTION
                        
                        '===============================================================================================
                        '// Returns 1 if a string is an alpha char (A-Z,a-z)
                        FUNCTION IsCapAlpha(s AS STRING) AS LONG
                        #REGISTER NONE
                        LOCAL sPtr&, sLen&
                           ON ERROR RESUME NEXT
                           sPtr = STRPTR(s)
                           sLen& = STRPTR(s) + LEN(s)
                           ! mov eax, sPtr ;ptr to string
                           ! mov ecx, sLen ;addr: end of string
                        StartLoop529:
                           ! mov bl, [eax]
                           ! cmp bl, 65
                           ! jl  NotAlpha529  ; < 65? Not alpha
                           ! cmp bl, 90
                           ! jg  NotAlpha529  ; > 90? Not alpha
                        Alpha529:
                           ! inc eax
                           ! cmp eax, ecx
                           ! je  EndLoop529
                           ! jmp StartLoop529
                        NotAlpha529:
                           FUNCTION = %False
                           EXIT FUNCTION
                        EndLoop529:
                           FUNCTION = %True
                        END FUNCTION
                        '===============================================================================================
                        FUNCTION IsAlpha(s AS STRING) AS LONG
                        #REGISTER NONE
                        LOCAL sPtr&, sLen&
                           ON ERROR RESUME NEXT
                           sPtr = STRPTR(s)
                           sLen& = STRPTR(s) + LEN(s)
                           ! mov eax, sPtr ;ptr to string
                           ! mov ecx, sLen ;addr: end of string
                        StartLoop530:
                           ! mov bl, [eax]
                           ! cmp bl, 65
                           ! jl  NotAlpha530  ; < 65? Not alpha
                           ! cmp bl, 122
                           ! jg  NotAlpha530  ; > 122? Not alpha
                           ! cmp bl, 91
                           ! jl  Alpha530     ; < 91? Alpha
                           ! cmp bl, 97
                           ! jl NotAlpha530   ; < 97? Not alpha
                        Alpha530:
                           ! inc eax
                           ! cmp eax, ecx
                           ! je  EndLoop530
                           ! jmp StartLoop530
                        NotAlpha530:
                           FUNCTION = %False
                           EXIT FUNCTION
                        EndLoop530:
                           FUNCTION = %True
                        END FUNCTION
                        '===============================================================================================
                        ' like IsNumeric, except allows a DASH
                        FUNCTION IsZIP(s AS STRING) AS LONG
                        #REGISTER NONE
                        LOCAL sPtr&, sLen&
                           ON ERROR RESUME NEXT
                           sPtr = STRPTR(s)
                           sLen& = STRPTR(s) + LEN(s)
                           ! mov eax, sPtr ;ptr to string
                           ! mov ecx, sLen ;addr: end of string
                        StartLoop534:
                           ! mov bl, [eax]
                           ! cmp bl, 45
                           ! je  OKgoon534   ;  is a dash
                           ! cmp bl, 48
                           ! jl  NotNumeric534  ; < 48? Not numeric
                           ! cmp bl, 57
                           ! jg  NotNumeric534  ; > 57? Not numeric
                        OKgoon534:
                           ! inc eax
                           ! cmp eax, ecx
                           ! je  EndLoop534
                           ! jmp StartLoop534
                        NotNumeric534:
                           FUNCTION = %False
                           EXIT FUNCTION
                        EndLoop534:
                           FUNCTION = %True
                        END FUNCTION
                        '===============================================================================================
                        '// Returns 1 if a string is alphanumeric (A-Z,a-z,0-9)
                        FUNCTION IsAlphanumeric(s AS STRING) AS LONG
                        #REGISTER NONE
                        LOCAL sPtr&, sLen&
                           ON ERROR RESUME NEXT
                           sPtr = STRPTR(s) - 1
                           sLen& = STRPTR(s) + LEN(s)
                           ! mov eax, sPtr ;ptr to string
                           ! mov ecx, sLen ;addr: end of string
                        StartLoop532:
                           ! inc eax
                           ! cmp eax, ecx
                           ! je  EndLoop532
                           ! mov bl, [eax]
                           ! cmp bl, 65
                           ! jl  NotAlpha532   ; < 65? Not alpha
                           ! cmp bl, 122
                           ! jg  NotNumeric532 ; > 122? Not NotNumeric
                           ! cmp bl, 91
                           ! jl  Alpha532      ; < 91? Alpha
                           ! cmp bl, 97
                           ! jl NotAlpha532    ; < 97? Not alpha
                        Alpha532:
                           ! jmp StartLoop532
                        NotAlpha532:
                           ! cmp bl, 48
                           ! jl NotNumeric532  ; < 48? Not numeric
                           ! cmp bl, 57
                           ! jg NotNumeric532  ; > 57? Not numeric
                           ! jmp StartLoop532
                        NotNumeric532:
                           FUNCTION = %False
                           EXIT FUNCTION
                        EndLoop532:
                           FUNCTION = %True
                        END FUNCTION
                        '===============================================================================================
                        ... .... . ... . . ... ... .... . .. ... .... .. ... .... .. .... ..

                        n6jah @ yahoo.com

                        Comment


                        • #13
                          I just found the Verify function too, which can be used as well.

                          Code:
                           
                          if Verify(MyString, "0123456789") = 0 then ? "Numeric"
                          Scott Slater
                          Summit Computer Networks, Inc.
                          www.summitcn.com

                          Comment


                          • #14
                            Code:
                              IF DATA-NAME IS {NUMERIC | ALPHABETIC |ALPHANUMERIC | SPECIAL-NAMES item } [THEN]
                            Wrong language (this is COBOL) but even that has 'gotchas' as NUMERIC does not permit for decimal points or plus/minus signs.

                            MCM
                            Michael Mattias
                            Tal Systems (retired)
                            Port Washington WI USA
                            [email protected]
                            http://www.talsystems.com

                            Comment


                            • #15
                              or multiple periods and minus signs
                              or minus signs and spaces in the wrong locations with the string
                              p purvis

                              Comment


                              • #16
                                New tricks

                                Since I found the fantastic VERIFY command a few month ago, ( by reading on that forum ) I have been using it in my test to validate all my inputs.

                                As I use a INKEY$ or WAITKEY$ loop to input each character one at a time, building the final operator input, it is possible to catch the mistake right at the source.

                                So, if you want to have only numeric input but with negative and dollar and cent I use :
                                Code:
                                if Verify(MyString, "-.0123456789") = 0 then ? "Numeric"
                                In my QB45, it took a lot more code to do that.
                                That technique will block any unwanted input as soon as it happen.

                                I think I will start to read all PowerBasic command one by one to check what I have been missing because of my ignorance.
                                As an old programmer, I have been guilty of using the old command I knew instead of switching to the new much better ones.

                                If anybody is interested, I could post my usual loop ?
                                Last edited by Guy Dombrowski; 12 Mar 2010, 07:39 PM.
                                Old QB45 Programmer

                                Comment


                                • #17
                                  Here's my tested function...

                                  Code:
                                  FUNCTION Str_IsLong(BYVAL Str AS STRING) AS LONG
                                      'Returns 1 if Str is a valid LONG.
                                      'Returns 0 of Str is not a valid LONG.
                                  
                                      FUNCTION = IIF&( _
                                          (LEN(Str) > 0) AND _                                        'Empty string not a valid LONG.
                                          (ISFALSE (VERIFY(Str, "-0123456789"))) AND _                'Only these characters valid.
                                          (ISFALSE (VERIFY(MID$(Str, 2), "0123456789"))) AND _        'Minus only valid in front.
                                          (VAL(Str) >= -2147483648) AND (VAL(Str) <= 2147483647) _    'Check range.
                                      , 1, 0)
                                  
                                  END FUNCTION
                                  Secret News | Mercury | Vaccines | Geoengineering | Utilities Made with PowerBasic

                                  Comment


                                  • #18
                                    Solves problem if multiple minus signs or multiple periods or period in last position.
                                    I'm not sure who wrote this, but here is a very good solution.

                                    Add range check to this if needed.
                                    Code:
                                     FUNCTION isNumeric(Answer AS STRING) AS LONG
                                      IF (LEN(Answer) = 0)                  OR _
                                         (VERIFY (Answer , ".-0123456789")) OR _
                                         (RIGHT$(Answer,1) = ".")           OR _
                                         (INSTR(-1,Answer,"-") > 1)         OR _
                                         (TALLY(Answer,".") > 1) THEN
                                         EXIT FUNCTION
                                      END IF
                                      FUNCTION = 1
                                    END FUNCTION
                                    Trimming the input field may be necessary if leading or trailing spaces.
                                    Code:
                                     FUNCTION isNumeric(Answer AS STRING) AS LONG
                                      Answer = TRIM$(Answer) 'may be required if right-justified text
                                      IF (LEN(Answer) = 0)                  OR _
                                         (VERIFY (Answer , ".-0123456789")) OR _
                                         (RIGHT$(Answer,1) = ".")           OR _
                                         (INSTR(-1,Answer,"-") > 1)         OR _
                                         (TALLY(Answer,".") > 1) THEN
                                         EXIT FUNCTION
                                      END IF
                                      IF LEN(Answer) > 10 THEN ? Answer,,"Answer"
                                      FUNCTION = 1
                                    END FUNCTION
                                    Last edited by Mike Doty; 11 Jun 2014, 06:48 PM. Reason: INSTR needed -1
                                    How long is an idea?

                                    Comment


                                    • #19
                                      deleted
                                      Last edited by Chris Holbrook; 11 Jun 2014, 06:50 PM.

                                      Comment


                                      • #20
                                        I reopened this very old post to post a solution not allowing multiple minus signs or periods or a period in last position.

                                        Added TRIM$(Answer) because my input may be right-justified and the spaces will cause it to fail.
                                        An example of why some other functions fail is they will report phone numbers as numeric:
                                        505-000-0000


                                        Code:
                                        FUNCTION isNumeric(Answer AS STRING) AS LONG
                                          Answer = TRIM$(Answer) 'may be required if right-justified text
                                          IF (LEN(Answer) = 0)                  OR _
                                             (VERIFY (Answer , ".-0123456789")) OR _
                                             (RIGHT$(Answer,1) = ".")           OR _
                                             (INSTR(-1,Answer,"-") > 1)         OR _
                                             (TALLY(Answer,".") > 1) THEN
                                             EXIT FUNCTION
                                          END IF
                                          FUNCTION = -1
                                        END FUNCTION
                                        Last edited by Mike Doty; 12 Jun 2014, 02:56 AM.
                                        How long is an idea?

                                        Comment

                                        Working...
                                        X