首页 > 解决方案 > 如果字符是 # 用 fscanf 注释,则跳过配置解析器中的行

问题描述

我已经编写了一个简单的配置解析器fscanf,现在想添加一个注释字符 ( #)。

我的配置文件包含三列,其中fscanf读取并存储在相应的数组中。这很好用,但我有点不确定如何编写它,以便“如果读取的字符#移动到下一行。

我尝试过使用fgetc,但这似乎只读取了第一个字符,并且它似乎破坏了我的 while 循环中的逻辑。

我尝试"%*[^\n]\n"在我的 fscanf 中使用以下修改:

while(fscanf(fp,"%d\t%f\t%f%*[^#]\n", &a[i], &b[i], &c[i]) != EOF)

但这会导致段错误。

配置:

#hello and welcome to my config file
1666    -0.314913523    0.999804843        #blah blah
1667    -0.337279687    0.999865966
1703    -0.323162231    0.999774194
1704    -0.311984064    0.99964375
1705    -0.311984064    0.99964375
1706    -0.313381260    0.999671436
1707    -0.313170802    0.999558174

代码:

#include <iostream>
using namespace std;

#define NUM_ITEMS 50

int main()
{
    FILE *fp;
    fp = fopen("config.conf","r");

    if(fp==NULL){
        printf("No file.\n");
        return -1;
    }

    int a[NUM_ITEMS];
    float b[NUM_ITEMS];
    float c[NUM_ITEMS];

    int i = 0;

    while(fscanf(fp,"%d\t%f\t%f", &a[i], &b[i], &c[i]) != EOF)
    {
        printf("-> %d   %f  %f\n", a[i], b[i], c[i]);
        i++;
    }

    fclose(fp);
}

标签: cconfigconfigparser

解决方案


您可以使用fgets将每一行作为字符串读取,然后检查“#”出现的位置。

#include <stdio.h>

#define NUM_ITEMS 50
#define MAX_CHAR 500

ssize_t find_index(char *str)
{
  size_t i=0U;

  for (; *str!='\0'; i++)
  {
    if (*str++=='#')
    {
      return i;
    }
  }

  return -1;
}

int main(void)
{
  int a[NUM_ITEMS];
  float b[NUM_ITEMS];
  float c[NUM_ITEMS];
  char buff[MAX_CHAR];
  FILE *fp;
  size_t i=0U;
  ssize_t index=0U;

  fp = fopen("config.conf","r");

  if(!fp)
  {
    printf("No file.\n");
    return -1;
  }

  while (fgets(buff,MAX_CHAR,fp))
  {
    index=find_index(buff);
    if (index!=-1)
    {
      buff[index]='\0'; /* Bare in mind this will skip the newline character which fgets appends */
    }

    if(sscanf(buff,"%d%f%f", &a[i], &b[i], &c[i])==3) /* Checking scanf read 3 numbers */
    {
      printf("-> %d %f %f\n", a[i], b[i], c[i]);
      i++;
    }
  }

  return 0;
}

所以find_index()返回元素#被发现的位置。然后用NULL终止符代替。

正如 Jonathan 在评论中指出的那样,您还可以使用该strcspn()函数以及strlen()(用于错误检查)来查找 # 的索引。


推荐阅读