【问题标题】:read only integers from complex string in c从c中的复杂字符串中读取整数
【发布时间】:2014-02-20 00:07:00
【问题描述】:

我试图只从字符串中读取整数。每次迭代时,空格和非整数字符基本上是随机的。理想情况下,我的代码将运行并仅打印(或以其他方式存储)整数。所以对于这个测试用例,它将是 6,1,0,16,2,3 等等。

char line [ 200 ] ="T06      1/ 0 16/ 2  3/15 41/40 17/36  0/11  0/11  0/11  1/14  1/ 7";
int num=0;
int count=0;
int i=0;
char *str = line;   

while (sscanf(str, "%d%n", &num,&i)){
      printf ("number: %d\n",num);
      str+=i;
      count++;
}

显然它不起作用,我认为我需要一种方法让 sscanf 跳过任何不是 0-9 的内容。有什么帮助吗?

谢谢

【问题讨论】:

  • 为什么不使用strtoul
  • 我建议将其读取为%c,然后检查您扫描的char 是否在 48 到 57 之间,它们是 ASCII 表中的整数

标签: c


【解决方案1】:

改成

while (sscanf(str, "%*[^0-9]%d%n", &num, &i)==1){
    printf ("number: %d\n",num);
    str+=i;
    count++;
}

【讨论】:

  • 如果字符串以数字开头,则循环将失败:(
【解决方案2】:

用空格替换所有非数字字符,然后将它们全部替换为scanf。您需要对负数进行调整,但我对此进行了测试,它为给定输入提供了您想要的输出。

char line [ 200 ] ="T06      1/ 0 16/ 2  3/15 41/40 17/36  0/11  0/11  0/11  1/14  1/ 7";
int num=0;
int count=0;
int i=0;
char *str = line; 

for (int i = 0; i < strlen(line); i++)
    if (!isdigit(line[i]))
        line[i] = ' ';

while (sscanf(str, "%d%n", &num,&i) == 1){
      printf ("number: %d\n",num);
      str+=i;
      count++;
}

【讨论】:

    【解决方案3】:
    #include <stdio.h>
    #include <string.h>
    #include <errno.h>
    #include <limits.h>
    #include <stdlib.h>
    
    enum oflow { OFL_GOOD, OFL_OVER, OFL_UNDER };
    
    int getnums(const char *str, int nums[], enum oflow oflow[], int n)
    {
      int i;
    
      for (i = 0; *str; ) {
        char *junk;
        long val;
    
        str += strcspn(str, "0123456789+-");
    
        if (!*str)
          break;
    
        errno = 0;
        val = strtol(str, &junk, 10);
    
        if (junk > str) {
          if (i < n) {
            if (((val == LONG_MIN) && errno == ERANGE) || (val < INT_MIN)) {
              nums[i] = 0;
              oflow[i++] = OFL_UNDER;
            } else if (((val == LONG_MAX) && errno == ERANGE) || (val > INT_MAX)) {
              nums[i] = 0;
              oflow[i++] = OFL_OVER;
            } else {
              oflow[i] = OFL_GOOD;
              nums[i++] = val;
            }
          } else {
            i++;
          }
          str = junk;
        } else {
          str++; /* no number was pulled out: skip one char and try again */
        }
      }
    
      return i;
    }
    
    int main(int argc, char **argv)
    {
      int nums[256];
      enum oflow oflow[256];
    
      if (argc > 1) {
        int n = getnums(argv[1], nums, oflow, 256);
        int i;
    
        if (n > 256) {
          printf("array is too small: we need %d elements\n", n);
          n = 256;
        }
    
        for (i = 0; i < n; i++) {
          if (oflow[i])
            printf("nums[%d] = %sflow\n", i, oflow[i] == OFL_OVER ? "over" : "under");
          else
            printf("nums[%d] = %d\n", i, nums[i]);
        }
      }
    
      return 0;
    }
    

    测试:

    $ ./nums "" $ ./nums "0" 数字[0] = 0 $ ./nums "-" $ ./nums "+" $ ./nums "+1" 数字[0] = 1 $ ./nums "-1" 数字[0] = -1 $ ./nums "abc" $ ./nums "asd+asdf+1 -0+1-3234abc-10zzz-" 数字[0] = 1 数字[1] = 0 数字[2] = 1 数字[3] = -3234 数字[4] = -10 $ ./nums "+++-1+++" 数字[0] = -1 $ ./nums "++" $ ./nums "1+11111111111111111111111-111111111111111111111" 数字[0] = 1 nums[1] = 溢出 nums[2] = 下溢 $ ./nums "$(seq 1 300)" |头-5 数组太小:我们需要 300 个元素 数字[0] = 1 数字[1] = 2 数字[2] = 3 数字[3] = 4 $ ./nums "$(seq 1 300)" |尾-5 数字[251] = 252 数字[252] = 253 数字[253] = 254 数字[254] = 255 数字[255] = 256

    作业练习:在什么情况下junk == strstrtol 之后,以使str++ 案例执行?为什么我们需要这个逻辑?

    【讨论】:

      【解决方案4】:

      要过滤除数字以外的所有内容,请在循环中使用 strcspn()sscanf()

      int i;
      while (sscanf(str += strcspn(str, "0123456789"), "%d%n", &num, &i) == 1) {
          printf("number: %d\n", num);
          count++;
          str += i;
      }
      

      【讨论】:

        【解决方案5】:

        sscanf 使用起来确实很痛苦,如果你的输入每次都不一样,那就更糟了。您可以尝试正则表达式,或者您可以尝试手动解析整数,如下所示:

        int i;
        int num = 0;
        int num_valid = 0;
        int count = 0;
        for(i = 0; line[i]; i++) {  // loop through every character
            if(line[i] >= '0' && line[i] <= '9') { // check to see if it's a digit
                num *= 10;                   // scale up num
                num += lin[i] - '0';         // convert ASCII to INT
                num_valid = 1;               // indicate that num contains a real number
        
            } else if(num_valid) {           // if the number is done
                printf ("number: %d\n",num);
                count++;
                num = 0;
                num_valid = 0;
            }
        }
        

        【讨论】:

          【解决方案6】:

          OP 差不多了!

          sscanf() 的字符串结尾和返回值添加测试。

          char line[200] = "T06 1/ 0 16/ 2  3/15 41/40 17/36  0/11  0/11  0/11  1/14  1/ 7";
          int num;
          int count = 0;
          char *str = line;   
          
          while (*str) {
            int i; // Place to save count of characters scanned.
            if (1 == sscanf(str, "%d%n", &num, &i)) {
              printf("number: %d\n", num);
              count++;
              str += i;
            } else {
              str++; // Go to the next character
            }
          }
          

          【讨论】:

            猜你喜欢
            • 2015-01-26
            • 2016-08-09
            • 1970-01-01
            • 2023-03-23
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多