【问题标题】:Trying to tweak sscanf() to ignore \n and \t [duplicate]试图调整 sscanf() 以忽略 \n 和 \t [重复]
【发布时间】:2018-11-03 15:36:11
【问题描述】:

我正在开发一个三角形计算并试图调整我的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]}

我需要解决什么问题?

【问题讨论】:

  • 您的str 是从fgets() 收到的吗? fgets() 在第一个换行符处停止读取...
  • if (!fgets(str, 100, stdin)) { // 错误 }
  • 那么这是什么类?

标签: c c89


【解决方案1】:

请注意,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() 无法告诉您它无法匹配格式字符串中的最终 ] 或 } — 您永远不会知道它们是否与当前格式匹配。

【讨论】:

  • 像往常一样,一个全面、正确、有用的答案。荣誉。
【解决方案2】:

正如 cmets 中所说,fgets 不会让您了解全部内容,而一次只能了解一行。作为连接多个fgets 读取的替代方法,如何按字符处理输入字符并使用} 作为终止:

#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

【讨论】:

    猜你喜欢
    • 2011-01-23
    • 1970-01-01
    • 2013-01-10
    • 2016-07-09
    • 2014-07-02
    • 2012-03-21
    • 1970-01-01
    • 2019-08-04
    • 1970-01-01
    相关资源
    最近更新 更多