重新分析C中的输入

时间:2017-07-22 05:24:23

标签: c parsing user-input scanf

我有一个"a b.c d.e"形式的输入(引号排除)我想要解析为a1=a, a2=b, a3=c,...等整数值。但技巧是"."之后的价值也可能丢失,因此"a b d.e""a b c""a b.c d"是有效输入。但是"a b. d.e"无效,因为"b"之后有一个".",但后面没有数字。假设数字即。 "a", "b"等是大于0且小于1000的整数。

我只能想到这样做的艰难方法。试过这个 - >

scanf("%d %2d[^. ].%2d[^. ] %2d[^. ].%2d[^\n]",&a,&b,&c,&d,&e);

但它不起作用。感谢您使用scanf()参数技巧解析它。

2 个答案:

答案 0 :(得分:1)

如果我理解您对我的评论的回答,那么在这种情况下,我不认为您可以将输入转换为scanf 格式字符串并处理您的变体想要处理。在这种情况下,你可以回到try和true,解析任何东西,strtol的帮助下沿着字符串向下走。

strtol提供结束指针,在输入字符串中有效转换为long后设置为下一个字符。因此,如果您正在按照复杂的输入字符串进行操作,则从strtol (p, &ep, 10)开始,其中p是指向字符串的指针,ep将设置为下一个字符。第一个转换后的字符串。 (在您的情况下为'.'' ')。如果下一个字符是'.',您可以对随后的字符进行进一步的测试,并在逐个收集值时确定输入字符串是否有效。

在您测试所需条件并提前ep指向要转换的下一个有效数字的开头之后,您只需设置p = ep;并重复,直到您填写a, b & c或点击错误的情况。

使用strtol时,除了检查errno之外,您还可以使用其他一些验证,但这对于此示例就足够了。有关其余验证,请参阅man strtol

如果我正确理解了你的逻辑,你可以做类似以下的事情:

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

#define MAXC 32

int main (void) {

    char buf[MAXC] = "", *p = buf, *ep = NULL;
    int a = 0, b = 0, c = 0, tmp = 0;

    printf ("enter values: ");
    if (!fgets (buf, MAXC, stdin))
        return 1;

    for (;;) {
        tmp = strtol (p, &ep, 10);
        if (errno) {    /* minimal conversion validation */
            fprintf (stderr, "error: failed conversion.\n");
            return 1;
        }
        if (!a)         /* handle a */
            a = tmp;
        else if (!b) {  /* handle b */
            if (*ep && *ep == '.' && *(ep + 1) &&  *(ep + 1) == ' ') {
                fprintf (stderr, "error: invalid input = '.' alone.\n");
                return 1;
            }
            b = tmp;
            if (*ep && *ep == '.' && *(ep + 1) && 
                '0' <= *(ep + 1) && *(ep + 1) <= '9')
                ep++;
            else
                while (*ep && (*ep < '0' || '9' < *ep))
                    ep++;
            if (!*ep) {
                fprintf (stderr, "error: invalid input - no 'c'.\n");
                return 1;
            }
        }
        else if (!c) {  /* handle c */
            if (*ep && *ep == '.' && *(ep + 1) && 
                (*(ep + 1) == ' ' || *(ep + 1) == '\n')) {
                fprintf (stderr, "error: invalid input = '.' alone.\n");
                return 1;
            }
            c = tmp;
            break;
        }
        p = ep;
    }

    printf ("a : %d\nb : %d\nc : %d\n", a, b, c);

    return 0;
}

示例使用/输出

$ ./bin/triplet
enter values: 1 2.3 4.5
a : 1
b : 2
c : 3

$ ./bin/triplet
enter values: 1 2 3.4
a : 1
b : 2
c : 3

$ ./bin/triplet
enter values: 1 2 3
a : 1
b : 2
c : 3

$ ./bin/triplet
enter values: 1 2.3 4
a : 1
b : 2
c : 3

$ ./bin/triplet
enter values: 1 2. 3.4
error: invalid input = '.' alone.

仔细看看,让我知道我是否误解了你的评论。如果没有,请记住你可以通过简单地沿着字符串走一个指针(或一对指针)来解析任何东西。

答案 1 :(得分:1)

没有简单的方法可以将scanf()用于您的目的。如果您想要严格验证输入,则必须编写一个定制的解析器。

这是一个解决方案:

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

char *skipblanks(char *p) {
    while (isblank((unsigned char)*p)
        p++;
    return p;
}

int getnumber(char *p, char **pp, int *dest) {
    if (strchr("0123456789+-", *p) {
        long val;
        errno = 0;
        val = strtol(p, pp, 10);
        if (errno == 0 && *pp > p && val >= INT_MIN && val <= INT_MAX) {
            *dest = val;
            return 1;
        }
    }
    return 0;
}

int parseinput(char *p, int *a, int *b, int *c, int *d, int *e)) {
    return getnumber(p, &p, a)
       &&  (*p != '.' || getnumber(p + 1, &p, b))
       &&  isblank((unsigned char)*p)
       &&  getnumber(skipblanks(p), &p, c))
       &&  (*p != '.' || getnumber(p + 1, &p, d))
       &&  isblank((unsigned char)*p)
       &&  getnumber(skipblanks(p), &p, e))
       &&  *skipblanks(p) == '\n';
}

int main(void) {
    char buf[128];
    int a, b, c, d, e;
    int status;
    char *p;

    if (fgets(buf, sizeof buf, stdin)) {
        /* set default values for b and d */
        a = b = c = d = e = 0;
        if (parseinput(buf, &a, &b, &c, &d, &e)) {
            printf("a=%d, b=%d, c=%d, d=%d, e=%d\n, a, b, c, d, e);
        } else {
            printf("input format error\n");
        }
    } else {
       printf("no input\n");
    }
    return 0;
}