【问题标题】:How to extract numbers from string in c?如何从c中的字符串中提取数字?
【发布时间】:2012-11-15 14:29:52
【问题描述】:

假设我有一个类似ab234cid*(s349*(20kd 的字符串,我想提取所有数字234, 349, 20,我该怎么办?

【问题讨论】:

  • (1) 到目前为止你尝试过什么?(2) 你熟悉isdigit()
  • -123 算作数字吗? +123?

标签: c string


【解决方案1】:

你可以用strtol来做,像这样:

char *str = "ab234cid*(s349*(20kd", *p = str;
while (*p) { // While there are more characters to process...
    if ( isdigit(*p) || ( (*p=='-'||*p=='+') && isdigit(*(p+1)) )) {
        // Found a number
        long val = strtol(p, &p, 10); // Read number
        printf("%ld\n", val); // and print it.
    } else {
        // Otherwise, move on to the next character.
        p++;
    }
}

链接到ideone

【讨论】:

  • +1: 但为什么是long long val = strtol();?我宁愿使用 C99 的 strtoll() 或将 val 定义为 long :)
  • 实际上,由于他没有扫描-,我会unsigned longstrtoul。 =)
  • @HappyGreenKidNaps 这就是strtol 的第二个参数如此有用的原因。
  • @HappyGreenKidNaps:如果调用不成功,因为没有数字存在,p 的值不会被调用改变(或者更确切地说,它将被更新为相同的值以前有)。
  • 如果它有负数呢,比如 ab-234cid*??
【解决方案2】:

使用sscanf() 和扫描集的可能解决方案:

const char* s = "ab234cid*(s349*(20kd";
int i1, i2, i3;
if (3 == sscanf(s,
                "%*[^0123456789]%d%*[^0123456789]%d%*[^0123456789]%d",
                &i1,
                &i2,
                &i3))
{
    printf("%d %d %d\n", i1, i2, i3);
}

其中%*[^0123456789] 表示在找到数字之前忽略输入。请参阅http://ideone.com/2hB4UW 的演示。

或者,如果数字的数量未知,您可以使用%n 说明符记录缓冲区中读取的最后位置:

const char* s = "ab234cid*(s349*(20kd";
int total_n = 0;
int n;
int i;
while (1 == sscanf(s + total_n, "%*[^0123456789]%d%n", &i, &n))
{
    total_n += n;
    printf("%d\n", i);
}

【讨论】:

  • 提供的字符串是任意的,这可能不适用于随机数的整数。还是谢谢!
  • @CDT,第二个 sn-p 可以。
  • 为什么对输入234cid*(s349*(20kd不起作用?
  • 这不适用于正数
【解决方案3】:

这里使用sscanf的简单解决方案:

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

char str[256]="ab234cid*(s349*(20kd";
char tmp[256];

int main()
{

    int x;
    tmp[0]='\0';
    while (sscanf(str,"%[^0123456789]%s",tmp,str)>1||sscanf(str,"%d%s",&x,str))
    {
        if (tmp[0]=='\0')
        {
            printf("%d\r\n",x);
        }
        tmp[0]='\0';

    }
}

【讨论】:

    【解决方案4】:

    制作一个根据一个基本原则运行的状态机:当前字符是一个数字。

    • 当从非数字转换为数字时,您将初始化您的 current_number := number。
    • 当从一个数字转换到另一个数字时,您将新数字“移动”到:
      current_number := current_number * 10 + number;
    • 从数字转换到非数字时,输出 current_number
    • 当从非数字到非数字时,你什么都不做。

    可以进行优化。

    【讨论】:

    • 我对状态机不熟悉,但这给了我一些新的想法,非常感谢!
    【解决方案5】:

    如果数字由字符串中的空格分隔,那么您可以使用 sscanf()。因为,您的示例并非如此, 你必须自己做:

    char tmp[256];
    
    for(i=0;str[i];i++)
    {
      j=0;
      while(str[i]>='0' && str[i]<='9')
      {
         tmp[j]=str[i];
         i++;
         j++;
      }
      tmp[j]=0;
      printf("%ld", strtol(tmp, &tmp, 10));
      // Or store in an integer array
    

    }

    【讨论】:

      【解决方案6】:
      #include<stdio.h>
      #include<ctype.h>
      #include<stdlib.h>
      void main(int argc,char *argv[])
      {
      char *str ="ab234cid*(s349*(20kd", *ptr = str;
      while (*ptr) { // While there are more characters to process...
          if ( isdigit(*ptr) ) {
              // Found a number
              int val = (int)strtol(ptr,&ptr, 10); // Read number
              printf("%d\n", val); // and print it.
          } else {
              // Otherwise, move on to the next character.
              ptr++;
          }
      }
      
      }
      

      【讨论】:

      • 欢迎来到 Stack Overflow!虽然这段代码 sn-p 可以解决问题,但including an explanation 确实有助于提高帖子的质量。请记住,您正在为将来的读者回答问题,而这些人可能不知道您的代码建议的原因。也请尽量不要用解释性的 cmets 挤满你的代码,这会降低代码和解释的可读性!
      【解决方案7】:

      或者你可以做一个这样的简单函数:

      // Provided 'c' is only a numeric character
      int parseInt (char c) {
          return c - '0';
      }
      

      【讨论】:

      • 如果您决定回答一个具有完善且正确答案的旧问题,那么在当天晚些时候添加新答案可能不会给您任何功劳。如果您有一些独特的新信息,或者您确信其他答案都是错误的,请务必添加一个新答案,但是在提出问题很长时间后提供相同基本信息的“另一个答案”通常不会不会为你赢得太多荣誉。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多