【问题标题】:Reading spaces with sscanf使用 sscanf 读取空间
【发布时间】:2016-08-19 17:41:13
【问题描述】:

我正在尝试使用sscanf 读取一个字符串,以便在拆分文件时将此扫描的字符串用作文件名。

问题是sscanf 只读取到文件中出现的第一个空间,这通常会发生。但是,我在 Stack Overflow 中看到了许多关于如何让它读取这些空间的提示。

不幸的是,它们似乎都是同一个东西,只需在函数中添加一个%[^\t\n\0] 或类似的东西。

问题是这种方法对我不起作用,我无法确定原因;我尝试了在这里找到的所有提示,但没有一个有效。

如果有人可以帮助我确定问题,我将不胜感激。

代码如下:

int TAM_BUFFER = 75; 
int filecounter=1, linecounter=1;

int main(int argc, char *argv[]){

    char fileoutputname[15];
    char buffer[TAM_BUFFER];
    char buffer2[15];
    char buffer3[15];

    FILE *arquivo = fopen("Entrada.txt", "r");
    FILE *saida;

    sprintf(fileoutputname, "%s.txt", buffer2);
    saida = fopen(fileoutputname, "w");

    if(arquivo != NULL){

        while(fgets(buffer, TAM_BUFFER, arquivo)){
            if(linecounter==2){
                strncpy(buffer2,buffer,sizeof buffer2 - 1);
                buffer2[sizeof buffer2 - 1] = '\0';
            }

            if (strncmp(buffer,"NEWDAY",strlen("NEWDAY")) == 0){
                fclose(saida);
                linecounter = 1;
                filecounter++;
                sscanf(buffer2, "%s", &buffer3);
                printf("strlen(%s)=%d\n", buffer3, (int) strlen(buffer3));
                sprintf(fileoutputname, "%s.txt", buffer3);
                saida = fopen(fileoutputname, "w");
                if (!saida)
                    return 1;       
            }

            fprintf(saida,"%s\n", buffer);
            linecounter++;

        }
    }

    fclose(arquivo);
    fclose(saida);
    return 0;
}

*我想做的是获取文件的第二行并使用前 14 个字符作为文件名。

文件的输入是这个:

TAM 2000-03-07T14:00    22.78   5.50999 2   786 2.8 798 2.8 186 0.0 298 3.2
TAM 2000-03-08T14:01    22.78   5.50999 2   779 1.2 793 1.0 186 0.0 300 1.5
TAM 2000-03-07T14:02    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-07T14:03    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-07T14:04    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-17T14:05    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-07T14:06    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
NEWDAY
TAM 2000-03-08T14:09    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-07T14:10    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-07T14:11    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-09T14:12    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
NEWDAY
TAM 2000-03-09T14:13    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-31T14:14    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-01T14:15    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-01T14:16    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-01T14:17    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-01T14:18    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-02T14:19    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9

【问题讨论】:

  • 您能告诉我们您尝试解析的输入吗?
  • 另外,做sscanf(buffer2, "%s", &buffer3)的真正目的是什么,除了获得第一个以空格分隔的“单词”?如果这不是目的,那么sscanf 调用只是做strcpy(buffer3, buffer2) 的不好方法。
  • 您好 Joachim,在我遵循您的指示并在经过一些测试后决定使用 sscanf 之前,您试图帮助我解决这个问题。现在我可以阅读说明,但只能读到第一个空格。输入是 TAM 2000-03-07T14:00 22.78 5.50999 2 786 2.8 798 2.8 186 0.0 298 3.2 我想读到 TAM 2000-03-07,但它在 TAM 中停止
  • 那么buffer2的内容应该已经包含了你想要的字符串。你试过打印出buffer2的内容吗?
  • 顺便说一句 sprintf(fileoutputname, "%s.txt", buffer2); : buffer2 未初始化。

标签: c string file space scanf


【解决方案1】:

如 cmets 中所述,您有许多字符串对于您声明的数组来说太长了。具体来说,您的数据文件行是75 字符长,不适合75 字符缓冲区。进行更改并稍微调整变量名称,您可以执行以下操作:

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

enum { BUFL = 20, TAMB = 80 };

int main (int argc, char **argv) {

    int fcnt = 1, lcnt = 1;
    char buf[TAMB] = "", buf2[BUFL] = "", buf3[BUFL] = "";
    char ofn[BUFL] = "";
    FILE *ifp = argc > 1 ? fopen (argv[1], "r") : stdin;
    FILE *ofp = argc > 2 ? fopen (argv[2], "w") : stdout;
    if (!ifp || !ofp) {
        fprintf (stderr, "error: file open failed.\n");
        return 1;
    }

    while (fgets (buf, TAMB, ifp)) {
        char *p = buf;
        for (; *p && *p !='\n'; p++) {} /* remove trailing \n */
        if (*p) *p = 0; /* overwrite '\n' with nul-terminator */

        if (lcnt == 2) {
            strncpy (buf2, buf, BUFL - 1);
            buf2[BUFL - 1] = 0;
        }

        if (strncmp (buf, "NEWDAY", strlen("NEWDAY")) == 0) {
            fclose (ofp);
            lcnt = 1;
            fcnt++;
            // sscanf (buf2, "%s", &buf3);
            strcpy (buf3, buf2);
            printf ("strlen (%s) = %zu\n", buf3, strlen (buf3));
            sprintf (ofn, "%s.txt", buf3);
            ofp = fopen (ofn, "w");
            if (!ofp)
                return 1;       
        }
        fprintf (ofp, "%s\n", buf);
        lcnt++;
    }

    if (ifp != stdin) fclose (ifp);

    return 0;
}

输入文件示例

$ cat dat/newday.txt
TAM 2000-03-07T14:00    22.78   5.50999 2   786 2.8 798 2.8 186 0.0 298 3.2
TAM 2000-03-08T14:01    22.78   5.50999 2   779 1.2 793 1.0 186 0.0 300 1.5
TAM 2000-03-07T14:02    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-07T14:03    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-07T14:04    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-17T14:05    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-07T14:06    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
NEWDAY
TAM 2000-03-08T14:09    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-07T14:10    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-07T14:11    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-09T14:12    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
NEWDAY
TAM 2000-03-09T14:13    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-31T14:14    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-01T14:15    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-01T14:16    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-01T14:17    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-01T14:18    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-02T14:19    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9

示例使用/输出文件

$ ./bin/readspaces dat/newday.txt dat/newdayout.txt
strlen (TAM 2000-03-08T14:0) = 19
strlen (TAM 2000-03-08T14:0) = 19

$ cat dat/newdayout.txt
TAM 2000-03-07T14:00    22.78   5.50999 2   786 2.8 798 2.8 186 0.0 298 3.2

TAM 2000-03-08T14:01    22.78   5.50999 2   779 1.2 793 1.0 186 0.0 300 1.5

TAM 2000-03-07T14:02    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9

TAM 2000-03-07T14:03    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9

TAM 2000-03-07T14:04    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9

TAM 2000-03-17T14:05    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9

TAM 2000-03-07T14:06    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9


$ cat TAM\ 2000-03-08T14\:0.txt
NEWDAY

TAM 2000-03-09T14:13    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9

TAM 2000-03-31T14:14    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9

TAM 2000-03-01T14:15    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9

TAM 2000-03-01T14:16    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9

TAM 2000-03-01T14:17    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9

TAM 2000-03-01T14:18    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9

TAM 2000-03-02T14:19    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9

注意:存在额外的行是因为您未能修剪fgets 读取并包含在buf 中的'\n'

修复换行问题后,您的输出文件为:

$ cat TAM\ 2000-03-08T14\:0.txt
NEWDAY
TAM 2000-03-09T14:13    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-31T14:14    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-01T14:15    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-01T14:16    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-01T14:17    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-01T14:18    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-02T14:19    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9

查看更改,如果您有任何问题,请告诉我。目前尚不清楚您尝试使用 buffer2/3 大小实现的长度,但您可以调整 BUFL 常量以使其满足您的需求。另请注意,您可以简单地将buffer2 复制到buffer3,不需要snprintf 语句。


似乎15 间隔会为代码的outputfilename 部分产生所需的结果。将BUFL 更改为15 提供:

$ ./bin/readspaces dat/newday.txt dat/newdayout.txt
strlen (TAM 2000-03-08) = 14
strlen (TAM 2000-03-08) = 14

然后生成输出文件:

$ cat TAM\ 2000-03-08.txt
xt
TAM 2000-03-09T14:13    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-31T14:14    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-01T14:15    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-01T14:16    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-01T14:17    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-01T14:18    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9
TAM 2000-03-02T14:19    22.78   5.50999 2   773 3.0 788 3.8 186 0.1 300 0.9

注意:但是,输出文件开头的NEWDAY 的一些未定义行为不是xt

【讨论】:

  • 嘿@David,这部分代码是什么意思? FILE *ifp = argc &gt; 1 ? fopen (argv[1], "r") : stdin; FILE *ofp = argc &gt; 2 ? fopen (argv[2], "w") : stdout;不应该告诉输入文件吗?
  • 这只是一种要么打开并从argv[1]给出的文件名读取(如果没有文件名则从stdin读取给定)并写入由argv[2] 给定的文件,如果文件名由第二个参数给出(或默认为stdout)。这是一个懒人的测试方法,通过将输出发送到屏幕来确认它是你想要的,然后再实际给出文件名并写入文件:) 两者都使用 ternary 运算符(例如a = test ? &lt;if true value&gt; : &lt;if false value&gt;;) 简写 if, else。在许多不同的情况下很有用。
  • 它允许您使用./bin/readspaces dat/newday.txt dat/newdayout.txt 形式来读取/写入文件,或者,例如,./bin/readspaces &lt;dat/newday.txt 将输出转储到stdout
【解决方案2】:

基本上如:

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

int TAM_BUFFER = 75; 

int main(int argc, char *argv[]){
    char fileoutputname[15] = {0};
    char buffer[TAM_BUFFER];

    FILE *arquivo = fopen("Entrada.txt", "r");
    FILE *saida;

    if(arquivo == NULL){
        perror("fopen");
        exit(EXIT_FAILURE);
    }

    fscanf(arquivo, "%14c", fileoutputname);//first split file name
    saida = fopen(fileoutputname, "w");
    rewind(arquivo);

    while(fgets(buffer, sizeof buffer, arquivo)){
        if(strncmp(buffer,"NEWDAY", 6) == 0){ // strlen("NEWDAY") is 6
            long file_pos = ftell(arquivo);//or use fgetpos for large file, save file position
            fscanf(arquivo, "%14c", fileoutputname);//next file name
            fseek(arquivo, file_pos, SEEK_SET);//or use fsetpos (pair with fgetpos), restore file position
            saida = freopen(fileoutputname, "w", saida);//fclose(saida);saida=fopen(fileoutputname, "w");
        }
        fprintf(saida,"%s", buffer);//No add newline
    }
    fclose(arquivo);
    fclose(saida);
    return 0;
}

【讨论】:

  • 仍然会有问题,输入行是75 字符长。让TAM_BUFFER = 80; 和你的罚款。
  • @DavidC.Rankin 样本小于 70。
  • 他一定是修改了输入文件,我复制的文件正是75 每行字符。 (我已经发布了我从问题中复制的那个)也许他做到了。
  • @DavidC.Rankin 它似乎是空白实际上它是 TAB(尝试编辑链接)。不管怎样,说他会改变。
  • 在这种情况下使用fputs 比使用fprintf 更好。
【解决方案3】:

如果你决定放弃sscanf(),你可以改用fgets()..

#include <stdio.h>

int main()
{
    char buffer2[200] = "Name with Spaces";

    FILE *fp;
    fp = fmemopen (buffer2, strlen (buffer2), "r"); 

    char str[200];
    if ( fgets(str, 200, fp) != NULL ) 
    {
        printf("Scanned Name: %s \n", str );
    }
}

【讨论】:

  • 然后使用sprintf(fileoutputname, "%s.txt", str);里面的str?
  • 是的,请确保 fileoutputname 足够大,我认为您应该很高兴。
  • 您可能想从 fgets 缓冲区中删除 \n
  • 好吧,我已经用Buffer 完成了,然后我只是将这个Buffer 的前14 个字符复制到Buffer 2,因为我不需要所有字符。在此之后,我说Buffer 2 的最后一个字符是'\0',以便强制Buffer2 在第 14 个字符处结束。然后我照你说的做了,在sprintf(fileoutputname, "%s.txt", str); 中使用Buffer2 作为str,但它不起作用,甚至没有创建文件,这就是我尝试用sscanf 创建它的原因。使用sscanf 效果很好,但问题是它以第一个空格字符结尾。
  • 查看您的代码,在我的代码示例中,您可能需要使用 fmemopen 将数据放入 Filepointer fpFILE *fp;fp = fmemopen (buffer2, strlen (buffer2), "r");fgets(buffer3,200,fp);close(fp);将`buffer2`读入buffer3
猜你喜欢
  • 2011-02-20
  • 2012-06-06
  • 2016-08-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多