C语言:如何使用sscanf从字符串中获取数字?

4
最近我需要从一个字符串中提取一个数字,但在旧的 C 语言中并不支持像 strtok 这样的函数。我更喜欢使用 sscanf,但我不知道如何使用它。需要注意的是整数可以出现在任意位置(由用户定义)。
一般来说,以下是我希望的一个示例:
Input:
char * string = "He is 16 years old.";

Output:
16

2
你好,欢迎来到stackoverflow.com。请花些时间阅读帮助页面,特别是名为“我可以在这里问什么话题?”和“哪些类型的问题应该避免提问?”的部分。更重要的是,请阅读Stack Overflow问题清单。你可能还想了解一下SSCCE是什么 - Some programmer dude
“但在非常老的C语言上” - 你是个受虐狂吗? - Karoly Horvath
Game-Editor平台不支持更新版本的C语言 ^^. - Lively
我的慰问。只要它不是核心语言特性,你总可以使用现有的缺失部分实现。 - Karoly Horvath
4个回答

3

数字过滤和sscanf()的结合使用应该可以解决问题。

int GetNumber(const char *str) {
  while (!(*str >= '0' && *str <= '9') && (*str != '-') && (*str != '+') && *str) str++;
  int number;
  if (sscanf(str, "%d", &number) == 1) {
    return number;
  }
  // No int found
  return -1; 
}

需要处理溢出的数字的额外工作。

下面是一种较慢但严谨的方法

int GetNumber2(const char *str) {
  while (*str) {
    int number;
    if (sscanf(str, "%d", &number) == 1) {
      return number;
    }
    str++;
  } 
  // No int found
  return -1; 
}

实际上,我一直在尝试进展,最终编写了一个字符串转整数的函数:int strtoint(char source[]) { int multiplier = 1; int i, result; for (i=strlen(source)-1; i>=0; i--) { if(source[i] >= '0' && source[i] <= '9') { result = result + ((source[i]-'0') * multiplier); multiplier *= 10; } } return result; } - Lively
谢谢。我已经修复了这部分 :) 我还自己制作了strtok函数。如果我发布它是否有用,我不知道。 离题:如果我有2个声望,我可以回答我的帖子.. - Lively
1
@JasonC 当 *str < 0 时,isdigit(*str) 是未定义行为。(*str >= '0' && *str <= '9') 没有这个问题。另一种选择是使用 isdigit((unsigned char) *str),它可以处理大多数其他情况。 - chux - Reinstate Monica
1
@JasonC C语言将'0''9'定义为连续的,因此(*str >= '0' && *str <= '9')是正确的,无论是ASCII还是其他字符集,如'0' + value。在C中,static_cast<unsigned char>(*str)会导致编译错误,因为本帖已经标记了C语言。我猜你可能在想其他编程语言。 - chux - Reinstate Monica
1
@JasonC 参考:「在源代码和执行基本字符集中,上述十进制数字列表中每个字符的值都应比前一个大1。」C17dr § 5.2.1 3 - chux - Reinstate Monica
显示剩余5条评论

2

scanf尝试匹配一个模式……所以如果你知道字符串是“He is 16 years old.”其中16是你希望解码的整数。

(我认为您的输入字符串意味着格式有些自由。 我假设它是可预测的。)

{
char* inputstr = "He is 16 years old.";
int answer = 0;
int params = sscanf (inputstr, "He is %d years old.", &answer);
if (params==1)
    printf ("it worked %d",answer);
else
    printf ("It failed");
}

使用 sscanf,你只能得到Lively(OP)的这些信息。如果你要获取其他非标准输入,除了"He is x years old."之外的任何内容,sscanf都无法胜任。 - Utkan Gezer
给定的字符串就像例子一样。基本上用户只需随意编写带有整数的随机字符串。函数必须输出这些整数。这是否可能?我只看到类似的问题,答案是使用sscanf,但没有解释如何使用sscanf - Lively
通常输入字符串符合一些约定的语法。如果完全是自由格式,那么我会编写一个例程将输入字符串在空格之间分割成较小的字符串数组。然后遍历该数组,在每个元素上调用 scanf。Params 值返回我们示例中解码为 int(最多一个)的 %d 的数量。 - AnthonyLambert

1
#include <stdio.h>

int main() {
    char * string = "He is 16 years old.";
    int age;
    if(sscanf(string, "%*[^0123456789]%d", &age)==1)
        printf("%d\n", age);
    else
        printf("not found\n");
    return 0;
}

string 以像 "123abc" 这样的 int 开头时,会出现失败的情况。 - chux - Reinstate Monica

1
首先,您应该知道strtok函数也非常古老。它在C89标准中,但可能在此之前的许多实现中存在(例如1986年发布的4.3BSD中)。事实上,sscanf函数可能比strtok函数更新。

但是,如果您使用如此古老的编译器,并且实际上没有strtok函数,而且您的输入字符串不遵循问题中的确切格式,而可以更自由地形成(因此无法真正使用sscanf的模式匹配功能),那么您必须手动解析字符串。

这种手动解析实际上可能非常简单,只需循环遍历字符串,直到找到数字,然后收集所有连续的数字,同时构造数字。一旦得到非数字字符,就可以得到数字。当然,这只会获取字符串中的第一个数字。


编译器甚至比古老还要古老...不支持strtok,甚至上帝也不知道为什么。你的意思是将字符串转换为数组并设置比较,如果第一个字符是0-10,则返回它...如果不是,则跳到下一个? - Lively
@Lively 哦,我真的为你感到抱歉!但是没错,那就是要点。 - Some programmer dude
嗯,@Joachim,我得习惯这样做。看起来我要自己创建一个比较输入输出的函数。谢谢。 - Lively

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接