从生成的字符串中扫描

scanf from a generated string

我需要创建一个程序来逐行读取文件并在每一行中扫描一些数据。 例如在一行中:

# 2 (x1,y1)(x2,y2)

我需要 x1,y1 和 x2,y2 我的代码是

    char firstCharacter;
    char line[100];
    scanf("%c",&firstCharacter);
    while ((fgets(line, sizeof line, stdin) != NULL) && (line[0] != '\n')){
        if(firstCharacter == '#'){
            int nu_deadend;
            sscanf(line,"%d",&nu_deadend);
            for (int i = 0; i < nu_deadend; i++) {
                int x,y;
                sscanf(line,"(%d,%d)",&x,&y);
                printf("x: %d y: %d\n",x,y);
            }
        }
    }
    return 0;

但来自输入:

# 2 (2,3)(3,4)

它输出:

x:0 y:0
x:0 y:0

预期输出:

x:2 y:3
x:3 y:4

我做错了什么?

您正在阅读输入中的“#”。输入中剩余的内容(包括最初的“2”)被读入缓冲区。

与输入流相反,您使用的字符串 linesscanf(line,"%d",&nu_deadend); 之后仍然包含已经成功扫描的初始“2”,而不是在成功扫描时丢失它。

因此您尝试扫描“(...)”时需要考虑“2”。

例如喜欢

sscanf(line,"%*d (%d,%d)",&x,&y);

对于第一个“()”。

第二个要么需要更精细的忽略,要么需要在适当的索引处开始扫描字符串中的相关“(”。
由于您需要循环,因此精心忽略无济于事。您必须先搜索正确的“(”,然后进行扫描。

来自我的最高评论...

与从中断处继续的 scanf 不同,sscanf 将从给定的缓冲区开始。因此,您可能需要使用(例如)char *cp = line;,然后使用并推进 cp 以指向下一个标记。

sscanf 不适合这个,因为它 return 是 countnot消耗的字节数。

最好使用 fgetscpstrtok,并将 strtok 的 return 值传递给 sscanf

此外,您永远不会为第二行重置 firstCharacter(即我假设每行都以 # 开头)


这是重构后的版本。注释为:

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

#ifdef DEBUG
#define dbgprt(_fmt...)         printf(_fmt)
#else
#define dbgprt(_fmt...)         do { } while (0)
#endif

int
main(void)
{
    char *tok;
    char line[100];

    // FORMAT:
    //  # <count> (x,y)(x,y)...
    while (fgets(line, sizeof line, stdin) != NULL) {
        dbgprt("LINE: %s",line);

        // get first token
        tok = strtok(line," \n");
        if (tok == NULL)
            break;

        // this must be "#"
        if (*tok != '#')
            continue;

        // get the count
        int nu_deadend;
        tok = strtok(NULL," \n");
        sscanf(tok, "%d", &nu_deadend);
        dbgprt("NUM: %d\n",nu_deadend);

        // get "(x,y)(x,y)(x,y)"
        tok = strtok(NULL," \n");

        for (int i = 0; i < nu_deadend; i++) {
            int x, y;

            dbgprt("TOK: '%s'\n",tok);
            sscanf(tok, "(%d,%d)", &x, &y);
            printf("x: %d y: %d\n", x, y);

            // advance past the end of the current (x,y)
            tok = strchr(tok,')');
            if (tok == NULL)
                break;
            ++tok;
        }
    }

    return 0;
}

这是我使用的测试输入:

# 2 (2,3)(3,4)
# 3 (1,7)(9,2)(8,3)

调试输出如下:

LINE: # 2 (2,3)(3,4)
NUM: 2
TOK: '(2,3)(3,4)'
x: 2 y: 3
TOK: '(3,4)'
x: 3 y: 4
LINE: # 3 (1,7)(9,2)(8,3)
NUM: 3
TOK: '(1,7)(9,2)(8,3)'
x: 1 y: 7
TOK: '(9,2)(8,3)'
x: 9 y: 2
TOK: '(8,3)'
x: 8 y: 3

而且,这是干净的输出:

x: 2 y: 3
x: 3 y: 4
x: 1 y: 7
x: 9 y: 2
x: 8 y: 3