【问题标题】:Ignoring numbers with letters around them忽略周围有字母的数字
【发布时间】:2020-10-05 23:24:31
【问题描述】:
#include <stdio.h>
#include <ctype.h>

int main(void)
{
  const char *str = NULL;
  size_t len = 0;
  getline(&str,&len,stdin);
  int i = 0;
  unsigned int count = 0, tmp = 0;

  printf("%s\n", str);

  while (sscanf(&str[count], "%d %n", &i, &tmp) != EOF) {
    count += tmp;
    printf("number %d\n", i);
  }

  return 0;
}  

我在这里要做的是向用户询问一行整数(正数或负数),我只关心它们之间有空格的有效整数,如果输入了非数字字符它应该忽略它之后发生的事情。上面是我到目前为止所拥有的,但我有一些错误,我现在所拥有的也忽略了我想要的空白。查看 EXP 以获得更多说明。

EXP: 
input: 1 2 3 4a              desired output-> 1 2 3    my ouput-> 1 2 3 4 4  
input: 1 2 3 a4              desired output-> 1 2 3    my ouput-> 1 2 3 3
input: 1 2 3 a b c 4 5 6 7   desired output-> 1 2 3    my output-> 1 2 3 3 3 3 4 5 6 7 
Valid input EXP:
input:    12                   367 98 -3 -67      desired output-> 12 367 98 -3 -67

【问题讨论】:

  • 欢迎来到 SO!所以基本上你想提取字符串中的所有整数并将它们放入一个整数数组中?
  • 我打算把它们放到一个链表中,但为了简单起见,我们说数组。
  • 一次读取一行是正确的方法,但对于转换,strtol() 是合适的工具,利用endptr 参数来确定是否保留任何非数字或非空白字符转换后。您可以使用sscanf() 和%n 从str + count + n 向前扫描以检查非数字/非空白字符。
  • 嗯好的。我将尝试使用 strtol() 来代替,它看起来是更简单的方法。谢谢!

标签: c


【解决方案1】:

当您需要从缓冲区中提取数值时,您需要考虑strtoX()(其中X 可以是l、ul、f、d,对于strtol()等。)原因有两个。 (1) 这些函数旨在允许您通过提供指向字符串本身的指针参数以及在最后一个数字成功转换后更新为指向下一个字符的endptr 参数来实现这一点; (2) 这些功能为转换的各个方面提供了完整的错误检测。

由于endptr 参数被更新为最后一位转换后的数字,您只需遍历缓冲区,尝试转换,成功转换后,您只需将初始指针更新为endptr 和重复直到你用完字符。见man 3 strtol

由于endptr 已更新为指向转换后的最后一个数字,因此您可以简单地检查指向endptr 的字符是字符串的nul-terminating 字符还是!isspace(*endptr) 确定该组数字中是否包含非数字。

您的案例的一个简单实现是:

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>

#define MAXC 1024

int main (int argc, char **argv) {
    
    char buf[MAXC];     /* buffer to hold each line */
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
    
    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }
    
    while (fgets (buf, MAXC, fp)) {             /* read each line into buf */
        char *p = buf, *ep = p;                 /* pointers to use with strtol() */
        for (;;) {                              /* loop continually */
            errno = 0;                          /* reset errno */
            long val = strtol (p, &ep, 0);      /* attempt conversion to long */
            if (p == ep)                        /* check if no characters converted */
                break;
            else if (errno)                     /* check for under/overflow */
                break;
            else if (*ep && !isspace(*ep))      /* check next char for non-space */
                break;
            else
                printf (" %ld", val);           /* good all-digit conversion */
            
            p = ep;                             /* update pointer to endpointer */
        }
        putchar ('\n');                         /* tidy up with newline */
    }
    
    if (fp != stdin)   /* close file if not stdin */
        fclose (fp);
}

输入文件示例

$ cat dat/numwalpha.txt
1 2 3 4a
1 2 3 a4
1 2 3 a b c 4 5 6 7

使用/输出示例

$ ./bin/strtol_numonly dat/numwalpha.txt
 1 2 3
 1 2 3
 1 2 3

添加错误报告

如果失败,您可以简单地输出以endptr 开头的字符(上面的ep)来查看失败的原因。您可以包含一个预处理器指令,通过使用 DEBUG 定义打开/关闭错误报告,如果您愿意,例如

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>

#define MAXC 1024

int main (int argc, char **argv) {
    
    char buf[MAXC];     /* buffer to hold each line */
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
    
    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }
    
    while (fgets (buf, MAXC, fp)) {             /* read each line into buf */
        char *p = buf, *ep = p;                 /* pointers to use with strtol() */
        for (;;) {                              /* loop continually */
            errno = 0;                          /* reset errno */
            long val = strtol (p, &ep, 0);      /* attempt conversion to long */
            if (p == ep) {                      /* check if no characters converted */
#ifdef DEBUG
                fprintf (stderr, "error: no digits converted in '%s'.\n", p);
#endif
                break;
            }
            else if (errno) {                   /* check for under/overflow */
#ifdef DEBUG
                fprintf (stderr, "error: over/under-flow in conversion or '%s'.\n", p);
#endif
                break;
            }
            else if (*ep && !isspace(*ep)) {    /* check next char for non-space */
#ifdef DEBUG
                fprintf (stderr, "error: mixed alphanumeric '%s'.\n", ep);
#endif
                break;
            }
            else
                printf (" %ld", val);           /* good all-digit conversion */
            
            p = ep;                             /* update pointer to endpointer */
        }
        putchar ('\n');                         /* tidy up with newline */
    }
    
    if (fp != stdin)   /* close file if not stdin */
        fclose (fp);
}

然后使用-DDEBUG 编译以启用定义,您将拥有:

$ ./bin/strtol_numonly dat/numwalpha.txt
error: mixed alphanumeric 'a
'.
 1 2 3
error: no digits converted in ' a4
'.
 1 2 3
error: no digits converted in ' a b c 4 5 6 7
'.
 1 2 3

其中显示第一个案例失败是由于末尾的'a',第二个是由于"a4" 作为要转换的字符串,最后一个是因为"a b c 4 5 6 7" 是字符串中剩下的所有内容, 'a' 是下一个转换。

【讨论】:

    猜你喜欢
    • 2020-04-14
    • 1970-01-01
    • 2019-03-12
    • 2014-03-13
    • 2021-01-29
    • 2016-05-05
    • 1970-01-01
    • 2016-11-29
    • 1970-01-01
    相关资源
    最近更新 更多