C: fscanf - бесконечный цикл при совпадении первого символа - PullRequest
3 голосов
/ 30 сентября 2010

Я пытаюсь проанализировать текстовый файл (CSS) с помощью fscanf и извлечь все операторы, которые соответствуют этому шаблону:

@ import "some / file /where.css";

Для этого у меня настроен следующий цикл:

FILE *file = fopen(pathToSomeFile, "r");
char *buffer = (char *)malloc(sizeof(char) * 9000);

while(!feof(file))
{
    // %*[^@] : Read and discard all characters up to a '@'
    // %8999[^;] : Read up to 8999 characters starting at '@' to a ';'.
    if(fscanf(file, "%*[^@] %8999[^;]", buffer) == 1)
    {
        // Do stuff with the matching characters here.
        // This code is long and not relevant to the question.
    }
}

Это прекрасно работает, так как ОЧЕНЬ ПЕРВЫЙ символ в файле не является символом @. (Буквально, один пробел перед первым символом «@» в файле CSS заставит код работать нормально.)

Но если самый первый символ в файле CSS - это '@', то в отладчике я вижу бесконечный цикл - выполнение входит в цикл while, попадает в оператор fscanf, но не вводит 'if '(fscanf терпит неудачу), а затем продолжается через цикл навсегда.

Я полагаю, что моим форматерам fscanf может потребоваться некоторая настройка, но я не уверен, как поступить. Любые предложения или объяснения, почему это происходит?

Спасибо.

Ответы [ 3 ]

2 голосов
/ 30 сентября 2010

Я не эксперт по scanf синтаксису паттернов, но моя ваша интерпретация такова:

  • Соответствует непустой последовательности не-'@' символов, затем
  • Соответствует непустой последовательности длиной до 8999 не- ';' символов

Так что да, если ваша строка начинается с '@', то первая часть завершится неудачей.

Я думаю если вы начнете строку форматирования с некоторого пробела, то fscanf сожрет любой начальный пробел в вашей строке данных, то есть просто " %8999[^;]".

1 голос
/ 30 сентября 2010

Оли уже сказал, почему fscanf не удалось. А так как сбой является нормальным состоянием для fscanf, ваш цикл занятости является не следствием сбоя fscanf, а отсутствующей обработкой для него.

Вы должны обработать ошибку fscanf, даже если ваш формат будет правильным (в вашем особом случае), потому что вы не можете быть уверены, что ввод всегда соответствует формату. На самом деле вы можете быть уверены, что существует гораздо больше несоответствующих входных данных, чем совпадающих входных данных.

0 голосов
/ 30 сентября 2010

Ваша строка формата выполняет следующие действия:

  • Чтение (и удаление) 1 или более не @ символов
  • Чтение (и удаление) 0 или более пробельных символов(из-за пробела в строке формата)
  • Чтение и сохранение от 1 до 8999 не ; символов

К сожалению, не существует спецификатора формата для чтения «ноль или более»"символы из пользовательского набора.

Если вас не волнует несколько операторов @include в строке, вы можете изменить код так, чтобы он читал одну строку (с помощью fgets), а затем извлекать @оператор include из этого (если первый символ не равен @, вы можете использовать текущую строку формата с sscanf, в противном случае вы можете использовать sscanf(line, "%8999[^;]", buffer)).

Если в строке несколько государственных деятелей @includeдолжны обрабатываться правильно, вы можете проверить следующий символ для чтения с помощью getc, а затем вернуть его с помощью ungetc.

...