如何在C中读取具有不同格式的多行TXT文件?

时间:2019-02-25 02:24:47

标签: c

我有一个输入文本文件,看起来像这样:

markers.id

我希望能够分别阅读每一行并区分它们。例如,对于第一行,我想将import firebase from '@firebase/app' import '@firebase/auth'; import '@firebase/database'; import '@firebase/storage'; 存储在一个变量中作为1(1.230000e+00) 2(1.230000e+00) (1.230000e+00 1.230000e+00) 3(1.230000e+00) (1.230000e+00 1.230000e+00) . . . ,而我想将100存储在另一个变量中,作为int。这是我尝试过的:

1.230000e+00

这适用于第一行。但是我该如何遍历所有行,并使用以下命令读取第三行:

double

为了提供上下文,在阅读每一行之后,我将进行一些处理,然后阅读下一行。根据行的格式,我将执行不同类型的处理。

感谢您的帮助!谢谢!

3 个答案:

答案 0 :(得分:2)

除非严格控制输入,否则

fscanf (3)几乎不可用。很难区分I / O错误和解析错误。这就是为什么使用 fgets (3)阅读每一行,然后使用 sscanf (3)进行扫描的原因。

由于 sscanf 返回已解析的元素数,因此您可以使用它来确定扫描是否按预期进行。无需窥视输入:如果您达到了预期,就完成了,否则尝试以其他方式进行扫描。这是一个工作示例:

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

int
main( int argc, char *argv[] ) {
  if( argc < 2 ) {
    errx(EXIT_FAILURE, "syntax: %s filename", argv[0]);
  }

  FILE *input = fopen(argv[1], "r");
  if( !input ) {
    err(EXIT_FAILURE, "could not open '%s'", argv[0]);
  }

  static char line[128];
  int n;

  while( fgets(line, sizeof(line), input) != NULL ) {
    double d1, d2;
    int quantum;

    if( 2 == sscanf(line, "%d(%lf)", &quantum, &d1) ) {
      printf( "ok: %d\t%7.2f\n", 100 * quantum, d1 );
    } else if( 2 == sscanf(line, "(%lf %lf)", &d1, &d2) ) {
      printf( "ok: %7.2f\t%7.2f\n", d1, d2 );
    } else {
      printf( ">>> %s\n", line );
    }

  }

  if( !feof(input) ) {
    err(EXIT_FAILURE, "error reading %s", argv[1]);
  }

  return EXIT_SUCCESS;
}

如果您发现其他模式,则可以轻松添加它们。请注意,当 fgets 失败时,仅当我们到达文件末尾时,程序才会返回成功。

答案 1 :(得分:0)

如评论中所述,您可以阅读整行,然后确定该行的格式并相应地解析该行。以下代码可以满足您的需求。但是,有价值的代码可能会更可靠地解释每行的格式。

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

char *GetStringNoBeginWhitespace( char *str )
{
    static const char whitespace[] = " \f\n\r\t\v";

    return(str + strspn(str, whitespace));
}

int main(int argc, char *argv[])
{
    char *line = NULL;
    FILE *fp;
    char buffer[255];

    int i;
    double d,d1;

    fp = fopen("data.txt", "r");

    while(fgets(buffer, 255, fp))
    {
        buffer[strlen(buffer)-1] = 0x00;
        line = GetStringNoBeginWhitespace( buffer );
        if( line )
        {
            fputs(line, stdout);
            if( isdigit((int)line[0] ))
            {
                printf("\tFormat is x(.......)\n");
                if( sscanf(line,"%d(%le)\n", &i, &d) == 2 )
                {
                    printf("      %d %le\n", i, d);
                }
                else
                {
                    printf("\tUnknown format....\n");
                }
            }
            else if( line[0] == '(' )
            {
                printf("\tFormat is ( ...... ....... )\n");
                if( sscanf(line, "(%le %le)\n", &d, &d1) == 2 )
                {
                    printf("      %le %le\n", d, d1);
                }
                else
                {
                    printf("\tUnknown format....\n");
                }
            }
            else
            {
                printf("\tUnknown format....\n");
            }
        }
    }

    fclose(fp); 
    return(0);
}

输出:

jnorton@ubuntu:~/source$ ./a.out 
1(1.230000e+00) Format is x(.......)
      1 1.230000e+00
2(1.230000e+00) Format is x(.......)
      2 1.230000e+00
(1.230000e+00 1.230000e+00) Format is ( ...... ....... )
      1.230000e+00 1.230000e+00
3(1.230000e+00) Format is x(.......)
      3 1.230000e+00
(1.230000e+00 1.230000e+00) Format is ( ...... ....... )
      1.230000e+00 1.230000e+00

data.txt文件:

1(1.230000e+00)
2(1.230000e+00)
(1.230000e+00 1.230000e+00)
3(1.230000e+00)
(1.230000e+00 1.230000e+00)

答案 2 :(得分:0)

如果生成文件,请为行长添加固定大小的前缀。例如。 name = forms.CharField(required=True, max_length=100, widget=forms.TextInput(attrs={'placeholder': 'Enter Name *'}), label=False) 。然后使用016:1(1.230000e+00)\n读取4个字节,使用fread将字符串转换为int并读取其余行(长度包括strtol)。最后用\n拆分值。