尝试调整sscanf()以忽略\ n和\ t

时间:2018-11-03 15:36:12

标签: c c89

我正在开发三角形计算,并尝试调整sscanf以忽略空格,换行符\n和制表符\t。我该怎么办?

我有:

if(sscanf(str, "{ [ %lf ; %lf ] , [ %lf ; %lf ] , [ %lf ; %lf ] }", &x_1, &y_1, &x_2, &y_2, &x_3, &y_3) == 6)

非常适合以下输入:

1) {[0;0],[19;10],[0;10]}

2) {     [  0 ; 0],             [12;0],[0    ;10]     }

但不适用于这样的事情

1) {
[
0
;
15
]
,   [   112 ;   0   ]   ,[112;15]}

我需要解决什么?

2 个答案:

答案 0 :(得分:2)

请注意,sscanf()默认情况下会忽略空白。格式字符串中的空格与零个或多个空格字符(空格,制表符,换行符)匹配。除了三个转换规范外,所有转换规范都会忽略前导空白-%c%[…](扫描集)和%n这三个例外-因此,对于格式字符串中的所有空白,空格和制表符都不会影响转换,除非第一个{之前有空格(您可以通过在{之前的格式字符串中添加空格来进行管理)。因此,问题可能不在sscanf()中,而是在数据中的字符中。

如果要使用fgets()读取数据,则需要将多行累积到单个字符串缓冲区中。如果您将sscanf()替换为scanf()fscanf(),则格式字符串将根据需要读取换行符(但是两者都会在右括号}之后保留任何换行符)由将来的输入操作读取)。当sscanf()处理数据时,字符串必须包含所有必需的字符,名义上直到}为止,尽管直到第六个数字的最后一位就足够了。

给出此代码-第三个字符串表示您在第三个多行数据中所说的内容(我假设开头的1)2)加上空格在问题中都是噪音,因为格式字符串不会尝试解析那些字符串):

#include <stdio.h>

static char *data[] =
{
    "{[0;0],[19;10],[0;10]}",
    "{     [  0 ; 0],             [12;0],[0    ;10]     }",
    "{\n[\n0\n;\n15\n]\n,   [   112 ;   0   ]   ,[112;15]}\n",
};
enum { NUM_DATA = sizeof(data) / sizeof(data[0]) };

int main(void)
{
    for (int i = 0; i < NUM_DATA; i++)
    {
        printf("String: @@%s@@@\n", data[i]);
        double x_1 = -9.9, y_1 = -9.9;
        double x_2 = -9.9, y_2 = -9.9;
        double x_3 = -9.9, y_3 = -9.9;
        int rc = sscanf(data[i], "{ [ %lf ; %lf ] , [ %lf ; %lf ] , [ %lf ; %lf ] }",
                        &x_1, &y_1, &x_2, &y_2, &x_3, &y_3);
        printf("rc = %d: ", rc);
        printf(" 1 = (%.1lf,%.1lf)", x_1, y_1);
        printf(" 2 = (%.1lf,%.1lf)", x_2, y_2);
        printf(" 3 = (%.1lf,%.1lf)", x_3, y_3);
        putchar('\n');
    }
    return 0;
}

我得到输出:

String: @@{[0;0],[19;10],[0;10]}@@@
rc = 6  1 = (0.0,0.0) 2 = (19.0,10.0) 3 = (0.0,10.0)
String: @@{     [  0 ; 0],             [12;0],[0    ;10]     }@@@
rc = 6  1 = (0.0,0.0) 2 = (12.0,0.0) 3 = (0.0,10.0)
String: @@{
[
0
;
15
]
,   [   112 ;   0   ]   ,[112;15]}
@@@
rc = 6  1 = (0.0,15.0) 2 = (112.0,0.0) 3 = (112.0,15.0)

如您所见,所有三个扫描操作均成功。这表明您认为您作为第三(多行)字符串所拥有的并不是您真正拥有的。

我建议对失败的数据进行逐字节转储,以查看问题出在哪里。另请注意,我捕获并打印了sscanf()的返回值;这将帮助您确定错误字符的位置。另外请注意,sscanf()无法告诉您它未能与格式字符串中的最后]}匹配-您永远不会知道它们是否与当前匹配格式。

答案 1 :(得分:0)

如评论中所述,fgets并不能使您获得全部收益,而一次只能获得一行收益。作为连接多个fgets的替代方法,如何按字符处理输入的char并使用}作为终止:

#include <stdio.h>

size_t get_tuple(char s[], size_t sz)
{
    int c;
    size_t i = 0;
    while (i < sz-1) {
        c = getchar();
        if (c == EOF) {
            break;
        }
        else {
            if (c != ' ' && c != '\t' && c != '\n') {
                s[i] = (char) c;
                ++i;
                if (c == '}') {
                    break;
                }
            }
        }
    }
    if (i < sz) {
        s[i] = '\0';
    }
    return i;
}

int main(void)
{
    char s[512];
    double x_1, x_2, x_3, y_1, y_2, y_3;
    size_t len;
    len = get_tuple(s, 512);
    while (len > 0) {
        printf("%s\n",s);
        if(sscanf(s, "{ [ %lf ; %lf ] , [ %lf ; %lf ] , [ %lf ; %lf ] }", &x_1, &y_1, &x_2, &y_2, &x_3, &y_3) == 6) {
            printf("read: x_1=%f, y_1=%f, x_2=%f, y_2=%f, x_3=%f, y_3=%f\n", x_1, y_1, x_2, y_2, x_3, y_3);
        }
        else {
            printf("scanf failed\n"); /* error */
        }
        len = get_tuple(s, 512);
    }
    return 0;
}

测试

输入文件

{[0;0],[19;10],[0;10]}

 {     [  0 ; 0],             [12;0],[0    ;10]     }

 {
[
0
;
15
]
,   [   112 ;   0   ]   ,[112;15]}

输出

$ ./main<test.txt 
{[0;0],[19;10],[0;10]}
read: x_1=0.000000, y_1=0.000000, x_2=19.000000, y_2=10.000000, x_3=0.000000, y_3=10.000000
{[0;0],[12;0],[0;10]}
read: x_1=0.000000, y_1=0.000000, x_2=12.000000, y_2=0.000000, x_3=0.000000, y_3=10.000000
{[0;15],[112;0],[112;15]}
read: x_1=0.000000, y_1=15.000000, x_2=112.000000, y_2=0.000000, x_3=112.000000, y_3=15.000000