只打印包含C中关键字的第一行和最后一行

只打印包含C中关键字的第一行和最后一行,c,pointers,extract,keyword,C,Pointers,Extract,Keyword,我上周开始学习C语言,即使是简单的任务对我来说也是一个挑战。目前我面临着这个问题:我有一个包含许多行的txt文件,每一行都以一个关键字开头(NMEA格式适用于那些知道它的人): $GPGGA,***001430.00***,。。。。。。。 $GPRMC,001430.00,。。。。。。。 $GPGSV,。。。。。。。。。。。。。。。。消息第一次到达时 $GPGSA,。。。。。。。。。。。。。。。。 ---------- $GPGGA,***005931.00***,。。。。。。。。。。。。。。

我上周开始学习C语言,即使是简单的任务对我来说也是一个挑战。目前我面临着这个问题:我有一个包含许多行的txt文件,每一行都以一个关键字开头(NMEA格式适用于那些知道它的人):

$GPGGA,***001430.00***,。。。。。。。
$GPRMC,001430.00,。。。。。。。
$GPGSV,。。。。。。。。。。。。。。。。消息第一次到达时
$GPGSA,。。。。。。。。。。。。。。。。
----------
$GPGGA,***005931.00***,。。。。。。。。。。。。。。。
$GPRMC,005931.00,。。。。。。。。。。。。。。。上次
$GPGSV,。。。。。。。。。。。。。。。。。。。。。。。。。
$GPGSA,。。。。。。。。。。。。。。。。。。。。。。。。。
我想提取$GPGGA行最后一次发生的时间戳。到目前为止,我只能提取文件的第一行和最后一行(不幸的是,最后一行不是GPGGA消息)。我试图在文件中查找关键字$GPGGA,然后从特定字节中提取字符串,并将值存储在一些变量(小时、分钟、秒)中

如有任何建议,将不胜感激。非常感谢您的时间和帮助

这是我的密码:

entint main(int argc,char**argv){
文件*opnmea;
char first[100],last[100];//消息到达的第一次和最后一次
整小时,分钟;
float sec;//观察时间
字符年[4],月[2],日[2];//obs活动的日期
焦时间[7];
opnmea=fopen(argv[1],“r”);
if(opnmea!=NULL){
fgets(first,100,opnmea);//只读文件的第一行
if(strstr(第一个“$GPGGA”)!=NULL)
{
sscanf(第一个+7、%2d%2d%f、&h、&min、&sec);
printf(“流的首次到达:%d%d%f\n”,小时、分钟、秒);
}
fseek(opnmea,0,SEEK_SET);
而(!feof(opnmea)){
if(strstr(第一个“$GPGGA”)!=NULL){
memset(last,0x00,100);//清除缓冲区
fscanf(opnmea,“%s\n”,最后一个);
}
}
printf(“流的最后到达:%s\n”,最后);
fclose(opnmea);
}
其他的
{
printf(“\n未找到文件%s”,argv[1]);
}
返回0;
}

scanf
函数族不知道换行符,它们被视为常规空格。如果您使用基于行的格式,最好使用
fgets
读取while行,然后进一步处理这些行,可能使用扫描字符串的
sscanf

不需要使用feof
。用于读取的库函数提供指示文件结尾的特殊值。例如,
fgets
将在出现错误或已到达文件末尾时返回
NULL

如果您只对时间戳感兴趣,则不必保存行。特别是,不需要两行缓冲区。提取并存储信息就足够了

下面的示例显示了查找时间戳的第一个和最后一个匹配项的基本工作原理。我将小时、分钟和秒合并为一个秒值

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



int main(int argc, char **argv)
{
    FILE *opnmea;
    float first = -1;         // first and ...
    float last = -1;          // ... last timestamp in seconds
    char line[100];

    if (argc != 2) {
        fprintf(stderr, "Usage: prog nmeafile\n");
        exit(1);
    }

    opnmea = fopen(argv[1], "r");

    if (opnmea == NULL) {
        fprintf(stderr, "Can't open '%s'.\n", argv[1]);
        exit(1);
    }

    while (fgets(line, sizeof(line), opnmea)) {
        int hrs, min;
        float sec;

        if (sscanf(line, "$GPGGA,%2d%2d%f", &hrs, &min, &sec) == 3) {
            sec = hrs * 3600.0 + min * 60.0 + sec;

            if (first < 0) first = sec;
            last = sec;
        }
    }

    printf("first: %8.2f sec\n", first);
    printf("last:  %8.2f sec\n", last);
    printf("diff:  %8.2f sec\n", last - first);

    fclose(opnmea);

    return 0;
}
#包括
#包括
#包括
int main(int argc,字符**argv)
{
文件*opnmea;
float first=-1;//first和。。。
float last=-1;/…以秒为单位的最后一个时间戳
字符行[100];
如果(argc!=2){
fprintf(stderr,“用法:prog-nmafile\n”);
出口(1);
}
opnmea=fopen(argv[1],“r”);
if(opnmea==NULL){
fprintf(stderr,“无法打开“%s”。\n”,argv[1]);
出口(1);
}
while(fgets(line,sizeof(line),opnmea)){
国际小时,分钟;
浮动秒;
如果(sscanf(行“$GPGGA,%2d%2d%f”、&hrs、&min、&sec)==3){
秒=小时*3600.0+分钟*60.0+秒;
如果(第一次<0)第一次=秒;
最后=秒;
}
}
printf(“第一个:%8.2f秒\n”,第一个);
printf(“最后一次:%8.2f秒\n”,最后一次);
printf(“差异:%8.2f秒\n”,最后一个-第一个);
fclose(opnmea);
返回0;
}

为什么
strstr(first,…)
fscanf(…,last)
要扩展@unwind所说的内容:您应该使用
fgets
一次读取整行内容,然后改为使用
sscanf
解析它。如果单行具有意外的格式,这将更加健壮。@EOF:他在代码中使用了
fscanf()
,请看一看。@JohnZwinck True,但在当前代码中,没有防止格式错误的行的保护,这会导致此处可能出现未定义的行为
printf(“流的首次到达:%d%d%f\n”,小时、分钟、秒)例如。因此,推荐
fgets()
+
sscanf()
虽然是一个很好的建议,但不会使代码更健壮,因为OP忽略了
fscanf()
sscanf()
的返回值。@EOF:我的评论的全部要点是,如果输入格式是意外的,代码不应该产生意外的结果。就这些,我们现在可以放下它了。@M哦,哇,非常感谢你的帮助。它是如此的整洁和清晰:)推荐
sec=hrs*3600+分钟*60+秒
(添加
0
)或3600.0以处理16位
int
@chux:yes。这是更传统的计算方法。修复了,谢谢。次要细节:3600.0对3600的建议是考虑到23*3600超出了最小的
int
范围。@chux:我通常不担心16位整数,但结果是一个浮点,所以使用浮点常量可能会更清楚。