确定字符串是包含实数值还是整数值的最快方法

时间:2008-12-26 19:31:03

标签: c++ optimization parsing

我正在尝试编写一个能够确定字符串是否包含实数或整数值的函数。

这是我能想到的最简单的解决方案:

int containsStringAnInt(char* strg){
  for (int i =0; i < strlen(strg); i++) {if (strg[i]=='.') return 0;}
  return 1;
}

但是当字符串很长时,这个解决方案真的很慢...任何优化建议? 真的很感激任何帮助!

8 个答案:

答案 0 :(得分:7)

您的实数的语法是什么?

1e-6对于文字是有效的C ++,但会在测试时作为整数传递。

答案 1 :(得分:3)

你的字符串是否有数百个字符?否则,不要关心任何可能的性能问题。 唯一的低效率是你以糟糕的方式使用strlen(),这意味着对字符串进行了大量的迭代(在strlen内部)。对于更简单的解决方案,具有相同的时间复杂度(O(n)),但可能稍快一些,请使用strchr()。

答案 2 :(得分:2)

你的函数没有考虑实数的指数表示法(1E7,1E-7都是双倍的)

使用strtol()尝试首先将字符串转换为整数;它还将返回解析失败的字符串中的第一个位置(如果数字为真,则为'。')。如果解析在'。'处停止,请使用strtod()尝试转换为double。同样,该函数将返回解析停止的字符串中的位置。

在分析程序之前,不要担心性能问题。否则,为了尽可能快的代码,构造一个描述可接受的数字语法的正则表达式,并将其首先手动转换为FSM,然后再转换为高度优化的代码。

答案 3 :(得分:2)

你正在使用strlen,这意味着你不担心unicode。在这种情况下,为什么要使用strlen或strchr,只需检查'\ 0'(空字符)

int containsStringAnInt(char* strg){ 

  for (int i =0;strg[i]!='\0'; i++) {
      if (strg[i]=='.') return 0;}   
  return 1; }

只有一个解析字符串,而不是在循环的每次迭代中解析字符串。

答案 4 :(得分:1)

首先是标准说明,如果还没有分析,请不要担心性能过高:)

我不确定手动循环和检查点。两个问题

  • 根据区域设置,点实际上也可以是“,”(德国就是这样的情况:):
  • 正如其他人所说,像1e7
  • 这样的数字存在问题

以前我在这里有一个使用sscanf的版本。但测量性能表明,对于更大的数据集,sscanf明显更慢。所以我会首先展示更快的解决方案(嗯,它也更简单。我在sscanf版本中有几个错误,直到我开始工作,而strto [ld]版本第一次尝试):

enum {
    REAL,
    INTEGER,
    NEITHER_NOR
};

int what(char const* strg){ 
    char *endp;
    strtol(strg, &endp, 10);
    if(*strg && !*endp)
        return INTEGER;
    strtod(strg, &endp);
    if(*strg && !*endp)
        return REAL;
    return NEITHER_NOR;
}

<子>
只是为了好玩,这是使用sscanf的版本:

int what(char const* strg) {
    // test for int
    { 
        int d;     // converted value
        int n = 0; // number of chars read
        int rd = std::sscanf(strg, "%d %n", &d, &n);
        if(!strg[n] && rd == 1) {
            return INTEGER;
        }
    }
    // test for double
    { 
        double v;     // converted value
        int n = 0; // number of chars read
        int rd = std::sscanf(strg, "%lf %n", &v, &n);
        if(!strg[n] && rd == 1) {
            return REAL;
        }
    }
    return NEITHER_NOR;
}

我认为这应该有效。玩得开心。

通过在循环中随机转换测试字符串(小字符串)10000000次来完成测试:

  • 6.6s for sscanf
  • 1.7 strto[dl]
  • {li> 0.5s代表manual looping直到“。”

strto[ld]的明确胜利,考虑到它会正确解析数字我会称赞它是手动循环的赢家。无论如何,1.2s / 10000000 = 0.00000012大致对于一次转换的差异最终并不是那么多。

答案 5 :(得分:0)

Strlen遍历字符串以查找字符串的长度。

你在循环的每次传递中调用strlen。因此,你走的字符串比必要的次数多很多倍。这个微小的变化应该会给你带来巨大的性能提升:

int containsStringAnInt(char* strg){
  int len = strlen(strg);
  for (int i =0; i < len; i++) {if (strg[i]=='.') return 0;}
  return 1;
}

请注意,我所做的只是在函数的开头找到一次字符串的长度,并在循环中重复引用该值。

请告诉我们这会给您带来哪些性能提升。

答案 6 :(得分:0)

@Aaron,你的方式也是你遍历字符串两次。一旦进入strlen,再次进入for循环。 for循环中ASCII字符串遍历的最佳方法是在循环中检查Null char。看一下我的答案,在for循环中只解析一次字符串,如果找到'',可能会部分解析。在结束之前。这样,如果一个字符串像0.01xxx(anotther 100 chars),你不需要一直到最后找到长度。

答案 7 :(得分:0)

#include <stdlib.h>
int containsStringAnInt(char* strg){ 
    if (atof(strg) == atoi(strg))
        return 1;
    return 0;
}