C接受有关传递关系的输入

时间:2018-10-29 11:59:05

标签: c input scanf c99

我如何接受这样的输入:

a<b
b<c

也这样:

a<b,c
d<e
f<x,y,z

目前,我能够读取像

我对单个语句的代码是:

char a, b;
while(scanf("%c<%c\n", &a, &b) == 2)
    /* Set alpha[0..26][0..26] to 1 */
    alpha[a - 'a'][b - 'a'] = 1;

我对每行多个语句尝试了类似的方法:

char a;
while(scanf("%c<", &a)) {
    char b;
    while(scanf("%c,", &b)) {
        if(getchar() == '\n') break;
        /* Set alpha[0..26][0..26] to 1 */
        alpha[a - 'a'][b - 'a'] = 1;
    }
}

但是它不能满足我的要求。它卡在第一个while循环中。 我对scanf以及在C语言中读取输入不是很好。因此,请提供一些帮助。

2 个答案:

答案 0 :(得分:2)

您可以使用getchar来解决它。

关注code可能会起作用:

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

int main(){
    int a;
    int b;
    char alpha[100][100];

    while ((a=getchar()) != EOF) {
        getchar(); // for <
        while((b=getchar()) != '\n') {
            /* Set alpha[0..26][0..26] to 1 */
            alpha[a - 'a'][b - 'a'] = 1;
            b = getchar();
            if (b == ',')
                continue;
            else
                break;
        }
    }
    return 0;
}

答案 1 :(得分:0)

将每个表达式读取为字符串,然后使用sscanf()%n模式对其进行解析,以获取解析部分的长度。 (请注意,%n未被大多数C库视为转换。)

例如:

#include <stdlib.h>
#include <stdio.h>
#define  STRINGIFY_(x) #x
#define  STRINGIFY(x)  STRINGIFY_(x)

#ifndef  MAX_WORD_LEN
#define  MAX_WORD_LEN  31
#endif
#define  SCAN_WORD "%" STRINGIFY(MAX_WORD_LEN) "[^\t\n\v\f\r <,;]"

const char *parse(const char *spec,
                  void      (*callback)(const char *less, const char *greater))
{
    char  less[MAX_WORD_LEN+1];
    char  more[MAX_WORD_LEN+1];
    int   len;

    while (1) {

        /* Skip an optional semicolon. */
        len = -1;
        if (sscanf(spec, " ; %n", &len) >= 0 && len > 0)
            spec += len;

        /* Try parsing the first pair. */
        len = -1;
        if (sscanf(spec, " " SCAN_WORD " < " SCAN_WORD " %n", less, more, &len) < 2 || len < 0)
            break;

        /* Report it. */
        if (callback)
            callback(less, more);

        /* Scan additional right sides. */
        spec += len;
        while (1) {

            len = -1;
            if (sscanf(spec, " , " SCAN_WORD " %n", more, &len) < 1 || len < 0)
                break; /* Only out of this inner while loop. */

            /* Report this one too. */
            if (callback)
                callback(less, more);

            spec += len;
        }
    }

    /* Return a pointer to the first unparsed character. */
    return spec;
}

将其应用于命令行上指定的每个表达式的示例程序:

void report(const char *left, const char *right)
{
    printf("    %s < %s\n", left, right);
}

int main(int argc, char *argv[])
{
    int         arg;
    const char *end;

    for (arg = 1; arg < argc; arg++) {
        printf("%s:\n", argv[arg]);

        end = parse(argv[arg], report);
        if (*end)
            printf("but with '%s' not parsed.\n", end);
        else
            printf("completely parsed.\n");
    }

    return EXIT_SUCCESS;
}

如果将上面的内容编译为example,然后运行

./example 'foo < bar foo < baz, war war < bar'

程序将输出

foo < bar foo < baz, war war < bar:
    foo < bar
    foo < baz
    foo < war
    war < bar
completely parsed.

也就是说,每个唯一对将调用一次回调函数(上面的report())。它接受“单词”作为名称,而不仅仅是单个字母。每个“单词”最多可以包含31个字符,并且可以包含除空格,<,;之外的任何字符。

为了完整起见,它允许在子表达式之间使用分号,并忽略它们。

逻辑本身很简单。

首先,parse()尝试扫描分号。周围的空白也会被跳过。

接下来,它尝试使用一对<来扫描一对“单词”。如果失败,它将跳出无限循环,并返回指向第一个未解析字符的指针。如果表达式的语法正确,它将指向一个NUL字节(\0)。

如果扫描了一对,则该对将调用回调函数(除非回调函数为NULL)。

接下来,一个内部循环尝试扫描逗号后跟“单词”。只要成功,就会为该对调用回调函数(使用原始的左侧,使用这个新的“单词”作为右侧)。否则,我们将跳出内循环,并开始新的外循环迭代。

因此,如果我们看foo < bar foo < baz, war war < bar,那么foo < bar将由外循环的第一次迭代进行解析; foo < baz将由外部循环的第二次迭代解析,, war由内部循环的解析;最后war < bar将由最外层循环的第三次迭代进行解析。