【问题标题】:Extract double from a string in c从c中的字符串中提取double
【发布时间】:2012-12-04 08:04:08
【问题描述】:

我想用 C 语言编写一个函数,它有一个字符串参数并返回一个双精度数。 例如,当字符串为fsldnf213414fasfa 时,它应该返回213414。 但它也应该能够将fasfasf123.412412fasfff 之类的浮点数返回为123.412412

我已经有一个只能提取整数而不是浮点数的函数:

double get_num(const char* s) 
{
    unsigned int limit = UINT_MAX / 10;
    double value = 0;
    if ( !s ) {
        return 0;
    }
    for ( ; *s; ++s ) {
        if ( value < limit ) {
            if ( isdigit(*s) ) {
                value *= 10;
                value += (*s - '0');
            }
        }
        else {
            return UINT_MAX;
        }
    }
    return value;
}

【问题讨论】:

  • 检查strtod
  • 我已经检查过了,但我还没有找到将其返回为双数的方法,只能提取为数字+浮点+数字。

标签: c floating-point double extract floating-point-conversion


【解决方案1】:

先跳过非数字,然后使用strtod将数字转换为double

double get_double(const char *str)
{
    /* First skip non-digit characters */
    /* Special case to handle negative numbers and the `+` sign */
    while (*str && !(isdigit(*str) || ((*str == '-' || *str == '+') && isdigit(*(str + 1)))))
        str++;

    /* The parse to a double */
    return strtod(str, NULL);
}

有关工作示例,请参阅 here

【讨论】:

  • 如果数字为负数会怎样?
  • @JasonD 啊当然...更新了答案以能够处理负数。
  • 现在它也不处理前导 '+' :)
  • @JasonD 现在可以了。 :) 不过你的答案可能更好。
  • 还有一些额外的混乱,'。'怎么样没有前导 0 ? :)
【解决方案2】:

您可以检查它是否解析了任何字符串,而不是使用 isdigit() 或其他事后猜测的 strtod():

char temp[] = "dgsgsd-3.5454dfds";

char *t1 = temp;
char *t2;
double d;

do
{
    if(*t1 == 0) return INVALID;
    d = strtod(t1, &t2);    
} while(t2 == t1++);

return d;

【讨论】:

  • 这里有同样的问题:但是如果字符串以数字开头怎么办?喜欢 12313asfa1231?我认为它会丢弃以下数字...
  • 是的,如果您希望字符串中有多个数字,则必须检查这些数字。您的函数只返回一个双精度值。如果您需要返回多个数字,无论如何这还不够,您需要返回一组数字或使用更新的输入多次调用它,直到字符串用完。
  • 好的,我明白了,你是对的。但是,如果我想要一张双人床怎么办?就像 123132afsaf123123 和 123132123123 一样。我可以提取第一个数字,但如何将这些“添加”到其余数字中?
  • strtod() 告诉你它在哪里完成了解析,所以这里给出的任何答案都可以更新,以最小的努力继续解析字符串中的其他数字。事实上,这种行为是我的答案的实际工作方式 - t2 将指向解析后的数字之后的下一个字符,并且可以传递回调用者或​​循环。
  • 啊,你希望单个数字被拆分?那不一样。您可以创建字符串的副本,去除无效字符,然后使用 strtod() 对其进行解析。但是我可以想象答案模棱两可的情况 - 所以我不确定问题是否明确。
【解决方案3】:
for (; *s; s++) {
    if (!isalpha(*s)) {
        value = strtod(s, NULL);
        break;
    }
}

结果:

"fasfasf-123.412412fasfff"
"fasfasf+123.412412fasfff"
"fasfasf.123412412fasfff"

-123.412412
123.412412
0.123412

【讨论】:

  • “dgsgsd%^&£.5454dfds”怎么样? :)
  • @JasonD 如果您期望输入,那么您必须使用较慢的方法
  • 问题中的输入没有很好地指定,因此很难知道哪个答案是最好的。但是,我会质疑我的方法是否慢得多 - 我想 strtod() 的检查与其他任何人一样有效,假设函数没有被内联,这只是函数调用开销的问题。根据实施情况,这可能非常少。除非性能是必要的并且这显示在基准测试中,否则我不会担心这里的速度......
  • @JasonD 你的总是有效的,我告诉你,但是从逻辑上讲,调用strtod 应该比在isalpha 中完成的简单范围检查做更多的工作,设置endptr,错误检查、更新errno 等...同样基于此,isalpha 和类似的函数更有可能被内联。但是,对于小字符串,开销是微不足道的,所以 +1。
  • 我认为您几乎可以肯定是正确的,尽管值得一提的是 isalpha() 确实会观察语言环境,因此在内部它不一定只是简单的范围检查。
【解决方案4】:

希望能帮到你。

double stringtof(char *s) {
  int i = 0, j, k = 0;
  int llen = 0;

  llen = strlen(s);
  for (i = 0; i < llen; i++) {
    if (isdigit(s[i]) == 1) {
      break;
    }
  }

  char str2[llen - i];

  for (j = i; j < llen; j++) {
    str2[k] = s[j];
    k++;
  }
  // * val=atof(str2);
  return (atof(str2));
}

ideone

【讨论】:

  • 输入如"-123" 转换为-123 和".25" 转换为0.25 失败。
【解决方案5】:

扩展@JasonD 使用strtod() 的好主意。

完整的有效字符串包括以下字符串以及可能的其他一些深奥的实现特定字符串。

"123.45"
" 123.45"
"+123.45"
"-123.45"
".45"
"INF"  (or maybe INFINTY)
"NAN"
"123,45"  (when , is the locale decimal point
"123e45"
"0x123p45"

然而,断言数字字符串不需要以控制字符或空格开头是合理的。

可以小心使用is....()函数来拒绝像isgraph()这样的非初学者。

isgraph 函数测试除空格 (' ') 之外的任何打印字符。

#include <ctype.h>
#include <stdlib.h>

// Return fail flag.
int seek_double_in_string(double *dest, const char *s) {
  if (s) {
    // Perhaps allow seek_double_in_string(NULL, s) ?
    double dummy;
    if (dest == NULL) {
      dest = &dummy;
    }

    while (*s) {
      if (isgraph(*(unsigned char*)s)) {  // Use s as-if it was `unsigned char *`
        char *endtpr;
        *dest = strtod(s, &endptr);
        if (s != endptr) {
          // Some conversion occurred - pedantic code might want to detect overflow.
          return false; // no error
        }
      }
      s++;
    }
  }

  // Form a default answer if desired like 0.0 or NAN
  *dest = 0;
  return true;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多