如何检查字符串代表的数字和数字类型?

时间:2012-01-27 23:27:50

标签: java optimization casting numbers

如何检查字符串是表示长,双还是常规字符串?我需要这样做,因为这个值需要根据其类型在数据库中建立索引。目前我这样做是通过尝试解析字符串并检查异常但由于代码被频繁调用,我想知道是否有更有效的方法来执行它。我的代码目前看起来像这样:

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

6 个答案:

答案 0 :(得分:3)

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

如果String包含除( - 在开头)和0-9或。之外的任何内容,则它是一个String。 (注意 - 这忽略了国际化和科学记数法 - 它们是否有问题?)

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

否则,它很长。

出于偏执,我仍然可以检查例外,但这可能是一种更快的方法。

注意添加我猜测测试正则表达式比从各种解析例程中抛出异常要快,但实际上这可能不是真的。你应该做一些测试。

答案 1 :(得分:2)

据我所知,除此之外没有优雅的方法可以做到这一点。我建议你按照最常见和最不常见的顺序解析它们,以便尽可能快地完成。

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

答案 2 :(得分:1)

您可以通过检查非数字以检测长时间来获得一些改进(特别是如果您可以排除科学记数法,例如1e12)。

Long.parseLong()委托一个在任何数字基础上工作的通用方法,因此只有十进制的方法可能会快一点。

如果您的数据中有可能,请不要忘记减号......

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

答案 3 :(得分:1)

您的代码看起来不错。

进行一些分析,如果基于它你发现你的代码太慢,那么你可以考虑潜在的优化(比如简单循环来查看所有字符是否都是数字)。

在分析之前不要尝试优化代码。特别是在像java这样的语言中。

答案 4 :(得分: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;
}

虽然使用它可能有点棘手。

答案 5 :(得分:0)

如果您不需要担心Longs为负面,可以使用Apache Commons Lang库中的NumberUtils.isDigits()NumberUtils.isNumber()

if(NumberUtils.isDidgets(string)){
    //Index long
} else if(NumberUtils.isNumber(string)){
    //Index double
} else {
    //Index string
}