我正在尝试编写一个能够确定字符串是否包含实数或整数值的函数。
这是我能想到的最简单的解决方案:
int containsStringAnInt(char* strg){
for (int i =0; i < strlen(strg); i++) {if (strg[i]=='.') return 0;}
return 1;
}
但是当字符串很长时,这个解决方案真的很慢...任何优化建议? 真的很感激任何帮助!
答案 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)
首先是标准说明,如果还没有分析,请不要担心性能过高:)
我不确定手动循环和检查点。两个问题
以前我在这里有一个使用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次来完成测试:
sscanf
strto[dl]
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;
}