计算给定字符串的浮点数的长度

Count the length of a float given string

假设您有一个变量 char s[30],并且 s 以正浮点数开头,例如 s = "15.016This is not a part of the float !";

浮点数后面的字符不能是数字。

目标是确定表示浮点数的字符数,例如|15.016| = 6.

我正在尝试编写一个简单的代码来执行此操作,最好不要使用任何外部库。

我有:

int count_len(char *s)
{
   char tmp_buf[30];
   int integral_digits = sprintf(tmp_buf, "%d", atoi(s) );
   return integral_digits + sprintf(tmp_buf, "%d", atoi(s + integral_digits +1) );
}

这适用于任何分数不包含前导零的数字(适用于 15.16,但不适用于 15.016)。

你会如何修复这个函数?

如果你有模式的输入字符串,

  "15.016This is not a part of the float !";

正如您在问题中提到的,我建议您使用 string.h 中可用的函数 strspn() or strcspn() 来找出 长度 领先的 float 类型。

如果使用strspn(),可以将accept设置为所有数字和点.

您不需要外部 库即可使用它们。它们是标准 Cglibc.

的一部分

C 用于黑客攻击,所以为什么不即时编写您的函数,例如:

size_t floatlenghth(char *s)
{
  size_t len = 0;
  short found_dot = FALSE;
  while ((*s >= '0' && *s <= '9') || (*s == '.' && !found_dot)) {
    len += 1;
    if (*s == '.') found_dot = TRUE;
    s++;
  }
  return len;
}

让事情变得复杂,

  • 您必须查看语言环境(如“,”表示小数点分隔符)。

    .. char dottype = getdottypeforlocale();

    .. if (*s == dottype)

  • 你想如何计算点后的前导零和尾随零(f.e。“001.200blubber”是长度 7 还是长度 3?)

    ... s = skipleadingzeros(s);

    ... /里面 while/ if (found_dot && *s == '0') counttrailingzeros++;否则 counttrailingzeros = 0;

    ... /while/ len -= counttrailingzeros;

  • 科学计数法:1.22E01

    ... 在 while() 之后看一下 iff *s = 'E' 并且接下来的两个字符是数字,然后添加 3

  • thousender-mark(s),例如 1'234.56(这在任何地方都有效吗?)或 1,234.56(英语)或 1.234,56(德语)或 1,234,567.89

int count_len(char *s){
    int len = 0;
    sscanf(s, "%*lf%n", &len);
    return len;
}

我在 3 分钟内写完了这篇文章。它有几个错误,例如,它在数字的右边计算零。这是您可以自己解决的问题:)

int count_len(const char *s)
{
    const int sz = strlen(s);
    int sz_of_float = 0;
    bool dot = false; // to avoid double dots like ".."
    for(int i = 0; i < sz; i++)
    {
        if(s[i] >= '0' && s[i] <= '9')
            sz_of_float++;
        else if(s[i] == '.' && dot == false)
        {
            dot = true;
            sz_of_float++;
        }
        else
            return sz_of_float;
    }
    return -1;
}

为什么不简单地使用带有临时格式说明符的 sscanf

考虑

sscanf("15.01336This is not a part of the float !", "%*f%n", &len);

%*f%n表示

  • %*f 读取一个浮点数 但不要将其存储 到任何地方,只使用它。
  • %n 存储到目前为止消耗的字符数

一个工作示例

#include <stdio.h>

int main()
{
    int len;

    sscanf("15.01336This is not a part of the float !", "%*f%n", &len);

    printf("%d\n", len);

    return 0;
}

以下是您对编写此类函数的算法的看法。

  1. 将计数设置为零。
  2. 如果第一个字符是非零数字,则将计数设置为 1。否则,退出并 return 为零。
  3. 从下一个字符开始,在遇到非数字字符或字符串末尾之前读入最大位数,每次递增计数。
  4. 如果到达字符串末尾,则退出并return 计数。否则,如果字符是句号,则计数加 1。
  5. 从句点后的下一个字符开始,在遇到非数字字符或字符串结尾之前读入最大位数,每次递增计数。
  6. Return 计数。

示例代码:

int countDigits(char const * str)
{
    int count = 0;
    int i;

    if (str == NULL) return 0;
    for (i = 0; str[i] != '[=10=]'; i++) {
        if (isdigit(str[i]))
            count++;
        else
            break;
    }
}

int countFloatChars(char const * str)
{
    int count = 0;

    if (str == NULL) return 0;
    if (str[0] == '[=10=]') return 0;

    if ((str[0] < '1') || (str[0] > '9')) return 0;

    count = 1;
    count += countDigits(str + count);

    if ((str[count] == '[=10=]') || (str[count] != '.')) return count;

    count++;
    count += countDigits(str + count);

    return count;
}

strtod 非常适合这个:

char *endOfFloat;
double val = strtod( str, &endOfFloat );
size_t len = (size_t) endOfFloat - str;

这假设字符串的浮点部分格式正确并且可以表示为 double

如果不是这种情况,您将需要不同的方法。

不使用 C 库,查找 (digits).(digits) 其中至少找到 1 个数字:

size_t float_length(const char *s) {
  const char *p = s;
  int digit_count = 0;

  // could add tests for white-space, +, - here        

  while (*p >= '0' && *p <= '9') {
    s++;
    digit_found = 1;
  }
  if (*p == '.') {
    p++;
    while (*p >= '0' && *p <= '9') {
      p++;
      digit_found = 1;
    }
  }
  if (digit_found) return (size_t) (p - s);
  return 0;
}

没什么好看的。