isNumber(string)方法的最佳实现

时间:2009-09-02 17:25:52

标签: c# performance

在我有限的经验中,我参与了几个项目,这些项目有一些字符串实用程序类,其中包含确定给定字符串是否为数字的方法。这个想法一直都是一样的,然而,实施却有所不同。有些使用try / catch

包围解析尝试
public boolean isInteger(String str) {
    try {
        Integer.parseInt(str);
        return true;
    } catch (NumberFormatException nfe) {}
    return false;
}

和其他人匹配正则表达式

public boolean isInteger(String str) {
    return str.matches("^-?[0-9]+(\\.[0-9]+)?$");
}

这些方法中的一种比另一种好吗?我个人更喜欢使用正则表达式方法,因为它很简洁,但是如果在迭代过程中调用,比如几十万个字符串的列表,它会在par上执行吗?

注意:由于我是网站的新手,我不完全理解这个社区Wiki业务,所以如果这属于那里,请告诉我,我很乐意移动它。

修改 有了所有的TryParse建议,我把Asaph的基准代码(感谢一个很棒的帖子!)移植到C#并添加了一个TryParse方法。而且看起来,TryParse赢得了胜利。然而,尝试捕获方法耗费了大量时间。我认为我做错了什么!我还更新了正则表达式来处理负数和小数点。

更新的C#基准代码的结果:

00:00:51.7390000 for isIntegerParseInt
00:00:03.9110000 for isIntegerRegex
00:00:00.3500000 for isIntegerTryParse

使用:

static bool isIntegerParseInt(string str) {
    try {
        int.Parse(str);
        return true;
    } catch (FormatException e){}
    return false;
}

static bool isIntegerRegex(string str) {
    return Regex.Match(str, "^-?[0-9]+(\\.[0-9]+)?$").Success;
}

static bool isIntegerTryParse(string str) {
    int bob;
    return Int32.TryParse(str, out bob);
}

19 个答案:

答案 0 :(得分:13)

我刚刚对这两种方法的性能进行了一些基准测试(在Macbook Pro OSX Leopard Java 6上)。 ParseInt更快。这是输出:

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

这是我的基准代码:


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.");
    }
}

另外,请注意您的正则表达式会拒绝负数,而parseInt方法会接受它们。

答案 1 :(得分:4)

以下是我们这样做的方法:

public boolean isNumeric(String string) throws IllegalArgumentException
{
   boolean isnumeric = false;

   if (string != null && !string.equals(""))
   {
      isnumeric = true;
      char chars[] = string.toCharArray();

      for(int d = 0; d < chars.length; d++)
      {
         isnumeric &= Character.isDigit(chars[d]);

         if(!isnumeric)
         break;
      }
   }
   return isnumeric;
}

答案 2 :(得分:3)

我需要重构像你这样的代码来摆脱NumberFormatException。重构的代码:

public static Integer parseInteger(final String str) {
    if (str == null || str.isEmpty()) {
        return null;
    }
    final Scanner sc = new Scanner(str);
    return Integer.valueOf(sc.nextInt());
}

作为Java 1.4的人,我不知道 java.util.Scanner 。我找到了这篇有趣的文章:

http://rosettacode.org/wiki/Determine_if_a_string_is_numeric#Java

我个人喜欢使用扫描仪的解决方案,非常紧凑且仍然可读。

答案 3 :(得分:3)

如果绝对性能是关键,并且如果你只是检查整数(不是浮点数)我怀疑迭代字符串中的每个字符,如果遇到不在0-9范围内的某些字符,则返回false最快的。

RegEx是一种更通用的解决方案,因此对于特殊情况可能执行速度不快。抛出异常的解决方案在这种情况下会有一些额外的开销。如果您实际上并不关心数字的值,TryParse将会略微慢,只是它是否是一个数字,因为转换为数字也必须发生。

除了多次调用的内部循环外,所有这些选项之间的差异应该是微不足道的。

答案 4 :(得分:2)

如果你真的想简化它,我个人会这样做。

public boolean isInteger(string myValue)
{
    int myIntValue;
    return int.TryParse(myValue, myIntValue)
}

答案 5 :(得分:2)

您可以为字符串创建扩展方法,并使整个过程看起来更干净......

public static bool IsInt(this string str)
{
    int i;
    return int.TryParse(str, out i);
}

然后,您可以在实际代码中执行以下操作...

if(myString.IsInt())....

答案 6 :(得分:2)

有些语言,比如C#,有一个TryParse(或同等版本),对于类似的东西,效果相当不错。

public boolean IsInteger(string value)
{
  int i;
  return Int32.TryParse(value, i);
}

答案 7 :(得分:1)

使用.NET,您可以执行以下操作:

private bool isNumber(string str)
{
    return str.Any(c => !char.IsDigit(c));
}

答案 8 :(得分:1)

public static boolean CheckString(String myString) {

char[] digits;

    digits = myString.toCharArray();
    for (char div : digits) {// for each element div of type char in the digits collection (digits is a collection containing div elements).
        try {
            Double.parseDouble(myString);
            System.out.println("All are numbers");
            return true;
        } catch (NumberFormatException e) {

            if (Character.isDigit(div)) {
                System.out.println("Not all are chars");

                return false;
            }
        }
    }

    System.out.println("All are chars");
    return true;
}

答案 9 :(得分:1)

这是我的实现来检查字符串是否由数字组成:

public static boolean isNumeric(String string)
{
    if (string == null)
    {
        throw new NullPointerException("The string must not be null!");
    }
    final int len = string.length();
    if (len == 0)
    {
        return false;
    }
    for (int i = 0; i < len; ++i)
    {
        if (!Character.isDigit(string.charAt(i)))
        {
            return false;
        }
    }
    return true;
}

答案 10 :(得分:1)

我喜欢代码:

public static boolean isIntegerRegex(String str) {
    return str.matches("^[0-9]+$");
}

但在使用它之前创建模式会更好:

public static Pattern patternInteger = Pattern.compile("^[0-9]+$");
public static boolean isIntegerRegex(String str) {
  return patternInteger.matcher(str).matches();
}

通过测试申请我们有结果:

This operation isIntegerParseInt took 1313 ms.
This operation isIntegerRegex took 1178 ms.
This operation isIntegerRegexNew took 304 ms.

使用:

public class IsIntegerPerformanceTest {
  private static Pattern pattern = Pattern.compile("^[0-9]+$");

    public static boolean isIntegerParseInt(String str) {
    try {
      Integer.parseInt(str);
      return true;
    } catch (NumberFormatException nfe) {
    }
    return false;
  }

  public static boolean isIntegerRegexNew(String str) {
    return pattern.matcher(str).matches();
  }

  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 isIntegerParseInt 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 isIntegerRegex " + (endtime - starttime) + " ms.");
    starttime = System.currentTimeMillis();
    for (int i = 0; i < iterations; i++) {
      isIntegerRegexNew("123");
      isIntegerRegexNew("not an int");
      isIntegerRegexNew("-321");
    }
    endtime = System.currentTimeMillis();
    System.out.println("This operation took isIntegerRegexNew " + (endtime - starttime) + " ms.");
  }
}

答案 11 :(得分:1)

我认为如果您执行以下操作(Java),它可能比以前的解决方案更快:

public final static boolean isInteger(String in)
{
    char c;
    int length = in.length();
    boolean ret = length > 0;
    int i = ret && in.charAt(0) == '-' ? 1 : 0;
    for (; ret && i < length; i++)
    {
        c = in.charAt(i);
        ret = (c >= '0' && c <= '9');
    }
    return ret;
}

我运行了Asaph运行的相同代码,结果是:

  

此操作耗时28毫秒。

一个巨大的差异(在我的电脑上,1691毫秒和2049毫秒)。请注意,此方法不验证字符串是否为空,因此您应该先执行此操作(包括字符串修剪)

答案 12 :(得分:1)

我认为这里的人们错过了一点。重复使用相同的模式具有非常容易的优化。只需使用模式的单例。这样做,在我的所有测试中,try-catch方法永远不会比模式方法有更好的基准。通过成功测试,try-catch需要两倍的时间,失败测试的速度要慢6倍。

public static final Pattern INT_PATTERN= Pattern.compile("^-?[0-9]+(\\.[0-9]+)?$");

public static boolean isInt(String s){
  return INT_PATTERN.matcher(s).matches();
}

答案 13 :(得分:0)

我使用这个,但我喜欢Asaph在帖子中的严谨性。

public static bool IsNumeric(object expression)
{
if (expression == null)
return false;

double number;
return Double.TryParse(Convert.ToString(expression, CultureInfo.InvariantCulture),   NumberStyles.Any,
NumberFormatInfo.InvariantInfo, out number);
}

答案 14 :(得分:0)

对于长数字使用此: (JAVA)

public static boolean isNumber(String string) {
    try {
        Long.parseLong(string);
    } catch (Exception e) {
        return false;
    }
    return true;
}

答案 15 :(得分:0)

 public static boolean isNumber(String str){
      return str.matches("[0-9]*\\.[0-9]+");
    }

检查数字是否(包括浮点数,整数)

答案 16 :(得分:0)

我之前回答的修改版本:

public static boolean isInteger(String in)
{
    if (in != null)
    {
        char c;
        int i = 0;
        int l = in.length();
        if (l > 0 && in.charAt(0) == '-')
        {
            i = 1;
        }
        if (l > i)
        {
            for (; i < l; i++)
            {
                c = in.charAt(i);
                if (c < '0' || c > '9')
                    return false;
            }
            return true;
        }
    }
    return false;
}

答案 17 :(得分:0)

我刚把这个类添加到我的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;
}
}

使用它:

TryParseLong valueAsLong = new TryParseLong(value);

if (valueAsLong.isParsable()) {
    ...
    // Do something with valueAsLong.getLong();
} else {
    ...
}

这只解析一次值。

它仍然通过异常使用异常和控制流,但至少它将这种代码封装在实用程序类中,使用它的代码可以更正常的方式工作。

Java与C#的问题在于C#具有值并通过引用传递,因此它可以有效地返回2条信息;指示某些内容是否可解析的标志,以及实际解析的值。当我们在Java中重新生成&gt; 1值时,我们需要创建一个对象来保存它们,所以我采用了这种方法并将标记和解析后的值放在一个对象中。

转义分析可能会有效地处理这个问题,并在堆栈上创建值和标志,并且永远不会在堆上创建此对象,因此我认为这样做对性能的影响很小。

根据我的想法,这给出了在保持控制流异常的代码,良好的性能以及不多次解析整数之间的最佳折衷。

答案 18 :(得分:0)

public static boolean CheckIfNumber(String number){

    for(int i = 0; i < number.length(); i++){
        try{
            Double.parseDouble(number.substring(i));

        }catch(NumberFormatException ex){
            return false;
        }
    }
    return true;     
}

之前我遇到过这个问题,但是当我输入一个数字然后输入一个字符时,它仍然会返回true,我认为这是更好的方法。只需检查每个字符是否都是数字。如果你有一个用户输入&#34; 1abc&#34;的情况需要更长时间。出于某种原因,当我试图在没有迭代的情况下尝试捕获时,它仍然认为它是一个数字...