2012-01-27 61 views
7

如何检查一个字符串是代表一个长整数,一个双整数还是一个常规字符串?我需要这样做,因为此值需要根据其类型在数据库中编入索引。目前我正在通过尝试解析字符串和检查异常来做到这一点,但由于代码被非常频繁地调用,所以我想知道是否有更高效的方法来执行此操作。我的代码目前看起来是这样的:如何检查字符串是否代表什么类型的数字?

String value = ...; 
// For example, could be "213678", "654.1236781", or "qwerty12345" 

try { 
    Long longValue = Long.parseLong(value); 
    // Index 'longValue' in the database 
} catch (NumberFormatException parseLongException) { 
    try { 
     Double doubleValue = Double.parseDouble(value); 
     // Index 'doubleValue' in the database 
    } catch (NumberFormatException parseDoubleException) { 
     // Index 'value' in the database 
    } 
} 

编辑:

我只是做了一个快速的基准测试按@ user949300的建议,使用正则表达式的模式,它的性能比上面的异常处理代码略胜一筹。下面是万一别人的代码,发现它有用:

Pattern longPattern = Pattern.compile("^[-+]?[0-9]+$"); 
Pattern doublePattern = Pattern.compile("^[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?$"); 

// Check for long regex pattern before the double regex pattern 
// since the former is a strict subset of the latter 
if (longPattern.matcher(value).matches()) { 
    // Perform indexing for long in the database 
} else if (doublePattern.matcher(value).matches()) { 
    // Perform indexing for double in the database 
} else { 
    // Perform indexing for string in the database 
} 

这里是检查了50 000个,其中的类型大致细分为50个%多头,10个%双打,40名%的字符串(代表工作量的基准测试结果我的应用程序进程):

--- Exception handling code --- 
STRING - actual: 19861, found: 19861 
DOUBLE - actual: 4942, found: 4942 
LONG - actual: 25197, found: 25197 
Time taken: 2561 ms 

--- Regex pattern matching code --- 
STRING - actual: 19861, found: 19861 
DOUBLE - actual: 4942, found: 4942 
LONG - actual: 25197, found: 25197 
Time taken: 1565 ms 
+0

如果您正在使用'java 7'而不是看看[multi-catch-blocks-for-exceptions](http://extreme-java.blogspot.com/2011/05/jdk-7 -multi-catch-blocks-for-exceptions.html) – RanRag 2012-01-27 23:38:16

+0

@RanRag我看不出在这种情况下multi-catch-blocks是如何有用的。第二个捕获是在第一个catch块之内 - 而不是在之后。 – emory 2012-01-27 23:54:53

+0

你是对的我没有看到。 – RanRag 2012-01-27 23:55:28

回答

3

您是否考虑过正则表达式?

如果字符串包含比其他任何东西 - (开头)和0-9或者,它是一个字符串。 (注 - 这忽略国际化和科学记数法 - 他们问题?)

否则,它包含了一个,它是一个双。 (那么,你应该只测试一个。,但这是一个开始)

否则,它是一个长。

出于偏执狂,我仍然可能会检查异常,但这可能是一种更快的方法。

补充说明我猜测测试正则表达式比抛出各种解析例程的异常更快,但这可能并不是真的。你应该做一些测试。

+0

我的印象是,正则表达式会更慢,但只是做了一个快速的基准测试练习,它使用正则表达式模式匹配多个长度和双精度,结果会稍微快一点。我已经将此代码与基准测试结果一起添加到了我的问题中。 – Dawood 2012-01-28 05:18:38

+0

谢谢你做了一个很好的基准。 – user949300 2012-01-28 05:41:34

2

据我所知,除此之外,没有其他的方法可以做到。我建议你按照最常见到最不常见的顺序对它们进行解析,以尽可能快地做到这一点。

如果你有超过3种可能的类型,你将会有一个深邃而丑陋的try-catch巢,但从技术上讲,它比将每个解析尝试分解成自己的方法要快;这里的权衡是你想要代码清晰还是更快执行 - 这听起来像你可能想要后者。

+0

如果我正确地理解了你,那么按照出现频率的顺序进行解析将不起作用,因为** String **表示将是** Double **的严格超集,而这又将是** Long * *。如果一个值应该很长,它仍然会成功解析为double而不会引发异常。 – Dawood 2012-01-28 01:46:26

+0

@达伍德:你说得对。我的观点是,应该考虑你解析的顺序,以便你可以(希望)避免一些工作。 – 2012-01-28 01:51:10

1

你也许能够得到一些改善的只是检查非数字来检测长(特别是如果你能排除科学记数法例如1e12)。

Long.parseLong()代表们,在任何数量的基础工作,所以小数,唯一的方法可能会快一点的一般方法。

不要忘了减号,如果这些是你的数据可能......

双打是很难,因为654.1236871是有效的,但654.12.36.87...1不大,但它们包含相同的字符集。因此可能需要完整解析。

1

你的代码看起来不错。

做一些分析,如果在此基础上你会发现你的代码速度太慢,那么你可以考虑一下潜在的优化(如简单的循环,看看是否所有字符是数字)。

不要试图剖析前,优化你的代码。特别是在像java这样的语言中。

1

一种可能性是java.io.StreamTokenizer中:

Reader r = new StringReader(value); 
StreamTokenizer st = new StreamTokenizer(r); 
int tokenType = st.nextToken(); 
double number; 
String word; 
switch (tokenType) { 
    case StreamTokenizer.TT_NUMBER: // it's a number 
     number = st.nval; break; 
    case StreamTokenizer.TT_WORD: // it's a string 
     word = st.sval; break; 
} 

它可以是一种棘手,虽然使用。

0

如果你不需要担心你Longs被否定,你也许可以使用NumberUtils.isDigits()NumberUtils.isNumber()从Apache下议院Lang库。

if(NumberUtils.isDidgets(string)){ 
    //Index long 
} else if(NumberUtils.isNumber(string)){ 
    //Index double 
} else { 
    //Index string 
} 
相关问题