【问题标题】:read lines from file with fgets and compare each line with strncmp in c使用 fgets 从文件中读取行并将每一行与 c 中的 strncmp 进行比较
【发布时间】:2017-01-02 15:21:00
【问题描述】:

我想从一个看起来像这样的文件中读取每一行:

readEveryLine
{       
  "Bart [m]" -> "Marge [f]";  
  "Lisa [f]" -> "Homer [m]"; 
  ...      
}

我想使用:

  1. fgets() 逐行读取文件
  2. strncmp() 将每一行与给定字符串进行比较或查看其格式是否正确

我有什么:

while(fgets(*file_string, MAX_INPUT_STDIN, file) != NULL)
{       
  changeLastC(*file_string);  // function to change \n into \0 

    if (strncmp(*file_string, "readEveryLine\0", 14) == 0)
    {
      if (strncmp(*file_string, "{\0", 2) == 0)
      {
        // check the first -> relation
      }
    }
    else
    {
      printf("Error Parsing\n");
    } 
}

所以问题是它只是给了我一个错误解析,我不知道我在这里做错了什么。

非常感谢您帮助我!

我现在在这里做了一些事情(现在解析前两行): 也许有人对我有一个很好的提示,我可以做得更好。 非常感谢。

if ((fp = fopen("df.dot","r")) == NULL)
{
  printf("Error: File Open\n");
  return 1;
}


int row = 0; // check row 1

while (fgets(buffer, MAX_PARSING, fp))
{        
  if ((row == 0) && strncmp(buffer, "readEveryLine\n", 14) == 0)
  {
    printf("%s", buffer);
  }
  else
  {
    printf("Parsing Error 1\n");
  }
}


int row1 = 1; // check row 2

while (fgets(buffer, MAX_PARSING, fp))
{     
  if ((row1 == 1) && strncmp(buffer, "{\n", 2) == 0)
  {
    printf("%s", buffer);
  }
  else
  {
    printf("Parsing Error 2\n");
  }
}


int row2 = 2; // check other rows (dynamic, could be even more or less)

while (fgets(buffer, MAX_PARSING, fp))
{ 
  if ((row2 == 2) && strncmp(buffer, "  ", 2) == 0)
  {
    const char *p1 = strstr(fp, "\"")+1;
    const char *p2 = strstr(p1, " [m]\"");
    const char *p3 = strstr(p1, " [f]\"");

    // extract male persons
    if (p1 && p2)
    {
      size_t len1 = p2 - p1;
      char* res1 = (char*)malloc(sizeof(char)*(len1 + 1));
      strncpy(res1, p1, len1);

      res1[len1] = '\0';

      // give res1 for functionMale() to work on that string
    }

    // extract female persons
    else if (p1 && p3)
    {
      size_t len2 = p3 - p1;
      char* res2 = (char*)malloc(sizeof(char)*(len2 + 1));
      strncpy(res2, p1, len2);

      res2[len2] = '\0';

      // give res2 for functionFemale() to work on that string
    }

    else if (strcmp(buffer, " -> ") == 0)
    {
      // work in progress (quite complicated to do this i think)
      // it has to be a realtion between two people
    }

    else if (strcmp(buffer, ";") == 0)
    {
      // work in progress
      // this sign can either exist like this:
      // "Bart [m]" -> "Marge [f]";

      // or like this:
      // "Marge [f]";
    }

    break;
  }
  else
  {
    printf("Parsing Error 3\n");
  }

  row2++;

}

// 最后一个符号必须是 }\n

【问题讨论】:

  • 1) stringchangeLastC() 的后定义,2) 确保编译器警告完全启用。 3) 为什么期望"readEveryLine\n" 等于"readEveryLine"?否则问题没有很好地说明。
  • 你到底为什么要使用strncmp?用于此目的的正确函数是strcmp
  • @chux,行尾没有'\n'。根据评论 \n 通过函数 changeLastC() 更改为 \0
  • @Gerhardh 是的,我的评论的第三部分应该不适用,但 cmets 不驱动代码 - 只提示需要什么。 OP 的问题很可能是由不起作用的changeLastC()string 的错误设置或许多其他原因引起的。发布的代码不足以诊断。
  • @chux,为什么不够?正如我在分析器中提到的那样,循环被打破了。除了“错误解析”之外,您永远无法得到任何东西。对于第一行,第一个 if 为真,但第二个 if 为假,因为任何字符串都不能匹配两个不同的文字。对于文件的每一行,第一个 if 已经为 false,我们输入打印“错误解析”的 else 部分。这就是他所说的错误。也许还有其他他没有提到的隐藏错误。但他首先需要解决这个问题。

标签: c file parsing fgets strncmp


【解决方案1】:

你的算法已经坏了。 您使用 *file_string 的相同内容将其与两个不同的字符串进行比较。 如果找到"readEveryLine" 的匹配项,则需要先从文件中读取下一行,然后才能获得strncmp() 的下一个匹配项。 否则文件中的行必须同时匹配"readEveryLine" "{" 才能通过第二个if 条件,这是不可能的。

编辑: 现在,由于您已经做了一些改进,我仍然认为它不适用于您的方法。循环不会在应该退出的时候退出,而且你的 if-else-cascade 似乎也不是一个好主意。 在你的方法中,你会因为阅读太多行而搞砸,而应该只解析 1 行。

也许您应该阅读一些有关状态机的知识。

这是我解决问题的快速方法:

enum { STATE_HEADER1, STATE_HEADER2, STATE_BODY, STATE_END} state;
int done = 0;
state = STATE_HEADER1;

while (fgets(buffer, MAX_PARSING, fp) && !done) {        
  if (state == STATE_HEADER1) {
    if (strcmp(buffer, "readEveryLine\n") == 0) {
      printf("%s", buffer);
      state = STATE_HEADER2;
    }
    else {
      printf("Parsing Error 1\n");
      done = 1;
    }        
  }
  else if (state == STATE_HEADER2) {
    if (strcmp(buffer, "{\n") == 0) {
      printf("%s", buffer);
      state = STATE_BODY;
    }
    else {
      printf("Parsing Error 2\n");
      done = 1;
    }
  }
  else if (state == STATE_BODY) {
    if (strcmp(buffer, "  ") == 0) {
      const char *p1 = strstr(buffer, "\"");
      const char *pm = strstr(p1, " [m]\"");
      const char *pf = strstr(p1, " [f]\"");
            char *res;
      const char *ptemp;
      int is_male;

      if (p1 && pf)  {
        p1 ++;
        is_male = 0;
        size_t len1 = pf - p1;
        res = malloc(len1 + 1);
        strcpy(res, p1);
        ptemp = pf+3; // point after closing \"

        // give res for functionFemale() to work on that string
      }
      else if (p1 && pm) {
        p1 ++;
        is_male = 1;
        size_t len1 = pm - p1;
        res = malloc(len1 + 1);
        strcpy(res, p1);
        ptemp = pm+3; // point after closing \"

        // give res for functionMale() to work on that string
      }
      else {
        done = 1;
        printf("Parsing Error 2\n");
      }

      // Now we have res and is_male holding name and gender.

      if (!done)
      {
        if (strncmp(ptemp, " -> ", 4) == 0) {

  // Handle this variant:
  // this sign can either exist like this:
  // "Bart [m]" -> "Marge [f]";

          // Do similar stuff as above for first name

          // Get second name + gender
          // Also check trailing ';' here
        }
        else if (strcmp(temp, ";\n") == 0) {

 // Handle this variant:
 // or like this:
 // "Marge [f]";

        }

      } // found "  "
      else {
        if (strcmp(buffer, "}\n") == 0) {
          state = STATE_END;
          done = 1;
          printf("That's it folks...\n"); 
        }
        else {
          done = 1;
          printf("Parsing Error 3\n");
        }
      }
    }
  } // STATE_BODY
} // while (fgets)

if (state == STATE_END) }
  // Success. :)
} else {
  // Something didn't match.
}

// close file, cleanup, etc.

我还没有编译它,但你应该明白了。

【讨论】:

  • 听起来很清楚。问题是,我不知道如何解析下一行,制作另一个 if 条件,然后解析第三行,制作下一个 if 条件等等。非常感谢您的帮助。
  • 例如,如果我使用这样的 while 循环:while(fgets(file_string, 19, file)) 并将此缓冲区用于第一行,那么我不确定是否应该使用循环每行和一个新缓冲区。我认为我错了。非常感谢您的帮助。
  • 用一些伪代码试试。试着向你的橡皮鸭或你的宠物解释你想做什么。您也可以尝试在纸上进行。如果有诸如“首先...,然后...”之类的短语,则需要一系列单独的操作。没有循环。如果有像“对于每一行......”这样的短语,那么你需要一个循环。有了这个,你应该清楚你的文件的前两行不需要循环。但是您需要为任何以下行创建一个循环。最后一行(“}\n”)的一些处理。我建议您再次深入阅读您的 C 教科书,并多了解一下 whenhow 循环的使用情况。
  • 你能给我一个解析 ; 的提示吗?在每行的末尾并解析字符串末尾的最后两个符号 }\n?这对我有很大帮助。谢谢。
  • 我已经更新了我的答案。您的方法仍然读取多行,而应解析同一行。您可能需要对最终细节进行一些调试。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多