Best implementation for an isNumber(string) method

前端 未结 19 2378
感动是毒
感动是毒 2020-12-15 20:04

In my limited experience, I\'ve been on several projects that have had some sort of string utility class with methods to determine if a given string is a number. The idea h

相关标签:
19条回答
  • 2020-12-15 20:08

    Using .NET, you could do something like:

    private bool isNumber(string str)
    {
        return str.Any(c => !char.IsDigit(c));
    }
    
    0 讨论(0)
  • 2020-12-15 20:14

    I just added this class to my utils:

    public class TryParseLong {
    private boolean isParseable;
    
    private long value;
    
    public TryParseLong(String toParse) {
        try {
            value = Long.parseLong(toParse);
            isParseable = true;
        } catch (NumberFormatException e) {
            // Exception set to null to indicate it is deliberately
            // being ignored, since the compensating action
            // of clearing the parsable flag is being taken.
            e = null;
    
            isParseable = false;
        }
    }
    
    public boolean isParsable() {
        return isParseable;
    }
    
    public long getLong() {
        return value;
    }
    }
    

    To use it:

    TryParseLong valueAsLong = new TryParseLong(value);
    
    if (valueAsLong.isParsable()) {
        ...
        // Do something with valueAsLong.getLong();
    } else {
        ...
    }
    

    This only parses the value once.

    It still makes use of the exception and control flow by exceptions, but at least it encapsulates that kind of code in a utility class, and code that uses it can work in a more normal way.

    The problem with Java versus C#, is that C# has out values and pass by reference, so it can effectively return 2 pieces of information; the flag to indicate that something is parsable or not, and the actual parsed value. When we reutrn >1 value in Java, we need to create an object to hold them, so I took that approach and put the flag and the parsed value in an object.

    Escape analysis is likely to handle this efficiently, and create the value and flag on the stack, and never create this object on the heap, so I think doing this will have minimal impact on performance.

    To my thinking this gives about the optimal compromise between keeping control-flow-by-exception out your code, good performance, and not parsing the integer more than once.

    0 讨论(0)
  • 2020-12-15 20:19

    I just ran some benchmarks on the performance of these 2 methods (On Macbook Pro OSX Leopard Java 6). ParseInt is faster. Here is the output:

    This operation took 1562 ms.
    This operation took 2251 ms.
    

    And here is my benchmark code:

    
    public class IsIntegerPerformanceTest {
    
        public static boolean isIntegerParseInt(String str) {
            try {
                Integer.parseInt(str);
                return true;
            } catch (NumberFormatException nfe) {}
            return false;
        }
    
        public static boolean isIntegerRegex(String str) {
            return str.matches("^[0-9]+$");
        }
    
        public static void main(String[] args) {
            long starttime, endtime;
            int iterations = 1000000;
            starttime = System.currentTimeMillis();
            for (int i=0; i<iterations; i++) {
                isIntegerParseInt("123");
                isIntegerParseInt("not an int");
                isIntegerParseInt("-321");
            }
            endtime = System.currentTimeMillis();
            System.out.println("This operation took " + (endtime - starttime) + " ms.");
            starttime = System.currentTimeMillis();
            for (int i=0; i<iterations; i++) {
                isIntegerRegex("123");
                isIntegerRegex("not an int");
                isIntegerRegex("-321");
            }
            endtime = System.currentTimeMillis();
            System.out.println("This operation took " + (endtime - starttime) + " ms.");
        }
    }
    

    Also, note that your regex will reject negative numbers and the parseInt method will accept them.

    0 讨论(0)
  • 2020-12-15 20:19

    If absolute performance is key, and if you are just checking for integers (not floating point numbers) I suspect that iterating over each character in the string, returning false if you encounter something not in the range 0-9, will be fastest.

    RegEx is a more general-purpose solution so will probably not perform as fast for that special case. A solution that throws an exception will have some extra overhead in that case. TryParse will be slightly slower if you don't actually care about the value of the number, just whether or not it is a number, since the conversion to a number must also take place.

    For anything but an inner loop that's called many times, the differences between all of these options should be insignificant.

    0 讨论(0)
  • 2020-12-15 20:19

    Some languages, like C#, have a TryParse (or equivalent) that works fairly well for something like this.

    public boolean IsInteger(string value)
    {
      int i;
      return Int32.TryParse(value, i);
    }
    
    0 讨论(0)
  • 2020-12-15 20:20

    Personally I would do this if you really want to simplify it.

    public boolean isInteger(string myValue)
    {
        int myIntValue;
        return int.TryParse(myValue, myIntValue)
    }
    
    0 讨论(0)
提交回复
热议问题