isNumber(string)方法的最佳实现

在我有限的经验中,我参与了几个项目,这些项目有一些字符串实用程序类,其中包含确定给定字符串是否为数字的方法。 这个想法一直都是一样的,然而,实施却有所不同。 有些使用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的基准代码(感谢一个很棒的post!)移植到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); } 

我刚刚对这两种方法的性能进行了一些基准测试(在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 

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

这是我们这样做的方式:

 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; } 

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

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

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

我需要重构像你这样的代码来摆脱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

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

有些语言,比如C#,有一个TryParse(或等价的),对于像这样的东西来说效果很好。

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

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

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

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

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

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

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

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

 private bool isNumber(string str) { return str.Any(c => !char.IsDigit(c)); } 
 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; } 

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

 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; } 

我喜欢代码:

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

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

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

我认为如果您执行以下操作(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毫秒)。 请注意,此方法不validation字符串是否为null,因此您应该先执行此操作(包括字符串修剪)

我认为这里的人缺少一点。 重复使用相同的模式具有非常容易的优化。 只需使用模式的单例。 这样做,在我的所有测试中,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(); } 

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

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

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

 public static boolean isNumber(String string) { try { Long.parseLong(string); } catch (Exception e) { return false; } return true; } 
  public static boolean isNumber(String str){ return str.matches("[0-9]*\\.[0-9]+"); } 

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

我以前的答案的修改版本:

 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; } 

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

这只解析一次值。

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

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

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

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

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,我认为这是更好的方法。 只需检查每个字符是否都是数字。 稍长一点,但如果您有用户输入“1abc”的情况,则需要注意。 出于某种原因,当我试图在没有迭代的情况下尝试捕获时,它仍然认为它是一个数字所以..