有没有办法检查字符串是否可以是C中的浮点数?

Elr*_*nnd 16 c string number-formatting

检查它是否可以是一个int很容易 - 只需检查每个数字是否在'0'和之间'9'.但浮动更难.我找到了这个,但没有一个答案真的有效.请考虑此代码段,基于顶部(已接受)答案:

float f;
int ret = sscanf("5.23.fkdj", "%f", &f);
printf("%d", ret);
Run Code Online (Sandbox Code Playgroud)

1 将被打印.


另一个答案建议使用strpbrk,检查是否存在某些非法字符,但这不会起作用,因为5fin7这不合法,但inf会.


另一个答案建议检查strtod的输出.但考虑一下:

char *number = "5.53 garbanzo beans"
char *foo;

strtod(number, &foo);

printf("%d", isspace(*foo) || *foo == '\0'));
Run Code Online (Sandbox Code Playgroud)

它会打印出来1.但我不想isspace完全删除呼叫,因为" 5.53 "应该是一个有效的号码.


有没有一种优雅,优雅,惯用的方式去做我想做的事情?

das*_*ght 12

第一个答案应该有效,如果你把它与%n它结合起来,这是读取的字符数:

int len;
float ignore;
char *str = "5.23.fkdj";
int ret = sscanf(str, "%f %n", &ignore, &len);
printf("%d", ret==1 && !str[len]);
Run Code Online (Sandbox Code Playgroud)

!str[len]如果字符串包含未包含的字符,则表达式将为false float.还要注意%f后跟空格的空格.

演示

  • 领先的空间是无害的,对称的,但没有必要; `%f`(与所有数字转换规范一样)无论如何都会跳过前导空格,无论你是否想这样做. (2认同)
  • @JonathanLeffler哇,这是一个很好的捕捉!非常感谢你!我想我可以通过将`len`设置为`strlen(str)+ 1来保存星号,但这是非常难以理解和非直观的,它会迫使我特殊情况下一个空字符串,所以我会去提出你的建议并使用一个被忽略的变量.谢谢! (2认同)
  • 事实上,如果`str`为空,`ret`可以是'EOF`.这是一个修复:`printf("%d",ret == 1 && str [len] =='\ 0');` (2认同)

Ste*_*ner 10

您可以检查 - 在使用读取值后strtod- 其余部分仅由空格组成.功能strspn可以在这里提供帮助,您甚至可以定义"您的个人空白区域"来考虑:

int main() {

    char *number = "5.53 garbanzo beans";
    char *foo;

    double d = strtod(number, &foo);
    if (foo == number) {
        printf("invalid number.");

    }
    else if (foo[strspn(foo, " \t\r\n")] != '\0') {
        printf("invalid (non-white-space) trailing characters.");
    }
    else {
        printf("valid number: %lf", d);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 嗯 - 它取决于:`double valid = 553.;`在c中有效. (2认同)

chu*_*ica 6

有没有办法检查字符串是否可以是浮点数?

sscanf(...,"%f")方法的一个问题是溢出,即UB.然而,它通常很好地处理.

而是使用 float strtof(const char * restrict nptr, char ** restrict endptr);

int float_test(const char *s) {
  char *ednptr;
  errno = 0;
  float f = strtof(s, &endptr);
  if (s == endptr)  {
    return No_Conversion;
  }
  while (isspace((unsigned char) *endptr)) {  // look past the number for junk
    endptr++;
  }   
  if (*endptr) {
    return Extra_Junk_At_End; 
  }

  // If desired
  // Special cases with with underflow not considered here.
  if (errno) {
    return errno; // likely under/overflow
  }  

  return Success;
}
Run Code Online (Sandbox Code Playgroud)


Jon*_*ler 5

该代码密切基于dasblinkenlight答案。我将其提供给大家深思。它给出的一些答案可能不是你想要的。

\n\n
#include <stdio.h>\n#include <string.h>\n\nstatic void test_float(const char *str)\n{\n    int len;\n    float dummy = 0.0;\n    if (sscanf(str, "%f %n", &dummy, &len) == 1 && len == (int)strlen(str))\n        printf("[%s] is valid (%.7g)\\n", str, dummy);\n    else\n        printf("[%s] is not valid (%.7g)\\n", str, dummy);\n}\n\nint main(void)\n{\n    test_float("5.23.fkdj");        // Invalid\n    test_float("   255.   ");       // Valid\n    test_float("255.123456");       // Valid\n    test_float("255.12E456");       // Valid\n    test_float("   .255   ");       // Valid\n    test_float("   Inf    ");       // Valid\n    test_float(" Infinity ");       // Valid\n    test_float("   Nan    ");       // Valid\n    test_float("   255   ");        // Valid\n    test_float(" 0x1.23P-24 ");     // Valid\n    test_float(" 0x1.23 ");         // Valid\n    test_float(" 0x123 ");          // Valid\n    test_float("abc");              // Invalid\n    test_float("");                 // Invalid\n    test_float("   ");              // Invalid\n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

使用 GCC 7.1.0 作为编译器在运行 macOS Sierra 10.12.6 的 Mac 上进行测试,得到输出:

\n\n
[5.23.fkdj] is not valid (5.23)\n[   255.   ] is valid (255)\n[255.123456] is valid (255.1235)\n[255.12E456] is valid (inf)\n[   .255   ] is valid (0.255)\n[   Inf    ] is valid (inf)\n[ Infinity ] is valid (inf)\n[   Nan    ] is valid (nan)\n[   255   ] is valid (255)\n[ 0x1.23P-24 ] is valid (6.775372e-08)\n[ 0x1.23 ] is valid (1.136719)\n[ 0x123 ] is valid (291)\n[abc] is not valid (0)\n[] is not valid (0)\n[   ] is not valid (0)\n
Run Code Online (Sandbox Code Playgroud)\n\n

十六进制数字可能特别有问题。各种形式的无穷大和非数字也可能很麻烦。255.12E456带有指数 ( )的示例溢出float并生成无穷大 \xe2\x80\x94 真的可以吗?

\n\n

这里提出的大多数问题都是定义性的\xe2\x80\x94,即你如何定义你想要接受的内容。但请注意,strtod()它将接受所有有效字符串(以及一些无效字符串,但其他测试会揭示这些问题)。

\n\n

显然,可以修改测试代码以使用包含字符串和所需结果的结构数组,并且这可以用于迭代显示的测试用例以及您添加的任何额外内容。

\n\n

对结果的强制转换strlen()避免了编译警告(错误,因为我使用 编译-Werror) \xe2\x80\x94 comparison between signed and unsigned integer expressions [-Werror=sign-compare]。如果您的字符串足够长,导致结果strlen()溢出有符号的int,那么您会遇到其他问题,假装它们是有效值。OTOH,您可能想尝试小数点 \xe2\x80\x94 后有效的 500 位数字。

\n\n

此代码记录了对 dasblinkenlight 的答案的评论:

\n\n\n