【问题标题】:Use sscanf to check number between range '0 ' , '9' ,'.' .'+ and '-' signs使用 sscanf 检查范围 '0' , '9' ,'.' 之间的数字.'+ 和 '-' 符号
【发布时间】:2018-02-12 18:31:01
【问题描述】:

如何使用 sscanf 检查字符串中的数字。我尝试了以下示例,它是可行的,但是我想知道如何包含带有点甲的数字,例如 3.6 和负号

#include <stdio.h>

int main() {
    char * string = "xx=3300   rr=3.6   zz=-0.8";
    int val;
    if(sscanf(string, "%*[^0123456789]%d", &val)==1)
        printf("%d\n", val);
    else
        printf("not found\n");
    return 0;
}

【问题讨论】:

  • 您打算如何在像val 这样的int 值中表示像3.6 这样的数字?似乎您应该为您的值和相应的格式说明符使用浮点类型(floatdouble)。
  • 不要使用scanf。使用strchr 扫描等号,然后使用strtod 将后面的内容转换为浮点数。
  • 如果string 以整数开头,sscanf(string, "%*[^0123456789]%d", &amp;val) 将不会返回 1,因为 "%*[^0123456789]" 在继续 "%d" 之前强制要求至少 1 个匹配字符。
  • 数字文本仅紧跟在'=' 之后还是可能出现在字符串的其他位置?

标签: c scanf


【解决方案1】:

如果只是扩展您的sscanf-方法,则只需添加-+.-字符,并使用数据类型floatdouble,它们可以表示浮点值:

int main() {
    char * string = "xx=3300   rr=3.6   zz=-0.8";
    float val;
    if(sscanf(string, "%*[^-+.0123456789]%f", &val)==1)
        printf("%f\n", val);
    else
        printf("not found\n");
    return 0;
}

然而,更好的方法是首先将字符串拆分为标记,例如基于空格或=-符号,这样您就可以准确地知道输入中您期望数字的位置;然后您可以将字符串转换为您选择的数字。这种方法可能如下所示:

int main() {
    char string[] = "xx=3300   rr=3.6   zz=-0.8";
    char *pair = strtok(string," ");
    while (pair) {
        char *beginOfVal = strchr(pair, '=');
        if (beginOfVal) {
            beginOfVal++;
            char *endOfVal;
            double val = strtod(beginOfVal, &endOfVal);
            if (endOfVal==beginOfVal) {
                printf("error scanning %s as a number.\n", beginOfVal);
            }
            else {
                printf("val: %lf\n", val);
            }
        }
        pair = strtok(NULL," ");
    }
}

【讨论】:

  • 实际上,出于线程安全的考虑,我需要避免使用 strtok,是否可以在不使用 strtok 的情况下使用第二种方法,是否有任何其他建议的函数来根据空间溢出字符串?! @Stephan Lechner
【解决方案2】:

您不应该为此使用sscanf,因为您应该使用never use any of the scanf functions for anything

您应该使用strchr 的组合来扫描等号,并使用strtod 将文本转换为机器浮点数。这是必要循环的草图:

void read_numbers_from_string (const char *str, void (*callback)(double))
{
    while (*str)
    {
        char *p = strchr(str, '=');
        if (!p) break;

        errno = 0;
        char *endp;
        double n = strtod(p + 1, &endp);
        if (endp > p + 1 && !errno)
            callback(n);

        str = endp;
    }
}

未经测试。围绕 strtod 处理错误可能不足以满足您的应用程序 - 请仔细阅读 strtod 手册页的 NOTES 部分。

【讨论】:

  • 请注意,OP 没有使用scanf()
  • @chux:请注意,情感(和推理)延伸到整个*scanf() 家庭。
  • @DevSolar scanf() 有很多sscanf() 没有的缺点。出于这些原因,我避开了scanf()sscanf() 的缺点很少,很容易处理。
  • @DevSolar strtod() 也有其弱点,因为它需要正确设置 errno 和各种电话后检查 - 这里没有显示。正确的工具通常需要正确的周围代码。
  • 这段代码似乎是一个无限循环,因为它正在执行strtod("=3300 rr=3.6 zz=-0.8", &amp;endp);。你想要p++; double n = strtod(p, &amp;endp);吗?
【解决方案3】:

strpbrk 可用于查找第一个数字、符号或点。使用strtolstrtod 解析

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    char * string = "xx=3300   rr=3.6   zz=-0.8  .89  4e-5";
    char *each = string;
    char *start = NULL;
    char *stop = NULL;
    long int val = 0;
    double dbl = 0.0;

    while ( ( start = strpbrk ( each, "0123456789.+-"))) {//find digit sign or dot
        val = strtol ( start, &stop, 10);//parse a long
        if ( '.' == *stop || 'e' == *stop) {//found a dot
            dbl = strtod ( start, &stop);//parse a double
            printf("%f\n", dbl);
        }
        else {
            printf("%ld\n", val);
        }
        if ( start == stop) {//unable to parse a long or double
            break;
        }

        each = stop;
    }
    return 0;
}

【讨论】:

  • 善用strpbrk()if ( start == stop) 应该在使用 valdbl 之前。
猜你喜欢
  • 1970-01-01
  • 2021-04-14
  • 2011-03-08
  • 1970-01-01
  • 2016-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多