читать строки из файла с помощью fgets и сравнивать каждую строку с помощью strncmp в c

я хочу прочитать каждую строку из файла, который выглядит примерно так:

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


person MBD    schedule 02.01.2017    source источник
comment
1) Опубликовать определение string и changeLastC(), 2) Убедитесь, что предупреждения компилятора полностью включены. 3) Почему ожидается, что "readEveryLine\n" будет равно "readEveryLine"? В противном случае проблема не точно определена.   -  person chux - Reinstate Monica    schedule 02.01.2017
comment
С какой стати вы хотите использовать strncmp? Правильная функция для этой цели — strcmp.   -  person rici    schedule 02.01.2017
comment
@chux, в конце строки нет '\n'. Согласно комментарию \n изменяется на \0 функцией changeLastC()   -  person Gerhardh    schedule 03.01.2017
comment
@Gerhardh Да, моя 3-я часть моего комментария должна не применяться, но комментарии не управляют кодом - только намекают на желаемое. Проблема ОП может быть вызвана неработающим changeLastC(), неправильной настройкой string или многими другими причинами. Приведенный код недостаточен для диагностики.   -  person chux - Reinstate Monica    schedule 03.01.2017
comment
@chux, почему этого недостаточно? Как я уже упоминал в своем ответе, петля разорвана. Вы никогда не сможете получить ничего, кроме синтаксического анализа ошибок. Для первой строки первое if истинно, а второе if ложно, потому что ни одна строка не может соответствовать двум разным литералам. Для каждой второй строки файла уже первая if является ложной, и мы вводим часть else, где печатается анализ ошибок. Это то, что он описывает как ошибку. Возможно, есть и другие скрытые ошибки, о которых он еще не упомянул. Но сначала ему нужно разобраться с этой проблемой.   -  person Gerhardh    schedule 03.01.2017
comment
@Gerhardh Примечание: ... любая строка не может соответствовать двум разным литералам. ...` --› strncmp(*file_string, "readEveryLine\0", 14) может возвращать совпадение ('0'), и использование другого строкового литерала strncmp(*file_string, "readEveryLine", 14) также может возвращать то же самое. Но это не главная проблема здесь.   -  person chux - Reinstate Monica    schedule 03.01.2017
comment
@чукс. Вы правы, если один литерал является подстрокой другого, это возможно. Но литералы, участвующие в задаче, построены иначе.   -  person Gerhardh    schedule 03.01.2017


Ответы (1)


Ваш алгоритм уже сломан. Вы используете одно и то же содержимое *file_string, чтобы сравнить его с двумя разными строками. Если вы найдете совпадение для "readEveryLine", вам нужно прочитать следующую строку из вашего файла, прежде чем вы сможете получить следующее совпадение для strncmp(). В противном случае строка из файла должна соответствовать как "readEveryLine" , так и "{", чтобы выполнить ваше второе условие if, что невозможно.

Изменить: теперь, когда вы сделали некоторые улучшения, я все еще думаю, что это не сработает с вашим подходом. Циклы не будут выходить, когда они должны, и ваш каскад if-else также не кажется хорошей идеей. В вашем подходе вы запутаетесь, прочитав слишком много строк, в то время как должна быть проанализирована только 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.

Я еще не компилировал его, но вы должны получить представление.

person Gerhardh    schedule 02.01.2017
comment
звучит ясно. проблема в том, что я не знаю, как разобрать следующую строку, сделать другое условие if, затем разобрать третью строку, сделать следующее условие if и так далее. Большое спасибо за твою помощь. - person MBD; 03.01.2017
comment
Например, если я использую такой цикл while: while(fgets(file_string, 19, file) ) и использую этот буфер для первой строки, то я не уверен, следует ли мне использовать цикл для каждой строки и новый буфер. я думаю, что я ошибаюсь в этом. Большое спасибо за твою помощь. - person MBD; 03.01.2017
comment
Попробуйте это с каким-нибудь псевдокодом. Попробуйте объяснить своей резиновой уточке или домашнему животному, что вы хотите сделать. Вы также можете попробовать сделать это на бумаге. Если есть фразы вроде сначала..., то... нужна последовательность отдельных действий. Нет петли. Если есть такие фразы, как Для каждой строки.... тогда вам нужен цикл. При этом должно быть понятно, что вам не нужен цикл для первых 2-х строк вашего файла. Но вам нужен цикл для любой следующей строки. И немного обработки последней строки (}\n). Я бы посоветовал вам снова порыться в учебнике по C и разобраться в том, когда и как используются циклы. - person Gerhardh; 03.01.2017
comment
не могли бы вы дать мне совет по разбору ; в конце каждой строки и разбор двух самых последних знаков }\n в конце строки? Это мне очень поможет. Спасибо. - person MBD; 05.01.2017
comment
Я обновил свой ответ. Ваш подход по-прежнему читает несколько строк, в то время как одна и та же строка должна быть проанализирована. Вам может понадобиться небольшая отладка для получения окончательных деталей. - person Gerhardh; 05.01.2017