Как прочитать следующую строку входного файла до конца файла без использования EOF - PullRequest
0 голосов
/ 20 февраля 2019

У меня есть входной файл (скажем, 10 строк) пар координат, каждая строка выглядит примерно так:

(1653408W, 503223N) (1651614W, 502806N)

Я пытаюсь перевести данные в формат DMS.Каждая строка во входном файле заканчивается символом \n, и я хотел бы пройтись по файлу и остановиться после последнего \n.Я думал о том, чтобы использовать что-то вроде:

while(fscanf(filename,
             "(%3d%2d%2d%c, %2d%2d%2d%c) (%3d%2d%2d%c, %2d%2d%2d%c)\n",
             &firstLonD, &firstLonM, &firstLonS, &firstLonC,
             &firstLatD, &firstLatM, &firstLatS, &firstLatC,
             &secLonD, &secLonM. &secLonS, &secLonC,
             &secLatD, &secLatM, &secLatS, &secLatC) == 16) {
//do something
}

Извините за условный длинный цикл и возможную плохую читабельность.Любые предложения о том, как поступить?

Ответы [ 3 ]

0 голосов
/ 20 февраля 2019
#include <stdlib.h>
File *file;
size_t len = 0;
ssize_t read;
char * line = NULL;     
while ((read = getline(&line, &len, file)) != -1)
{
    printf("%s",line);
    if(sscanf(line, "....format",...)==16)){
           ..............
     }
}
0 голосов
/ 20 февраля 2019

Пробелы и символы новой строки в строке формата fscanf НЕ соответствуют пробелам и символам новой строки во входных данных.Вместо этого любой символ пробела в формате означает «пропустить пробел», читая и отбрасывая пробел, пока не будет найден какой-либо непробельный символ - который может быть следующим символом, поэтому ничего не пропускается.Кроме того, большинство спецификаторов преобразования также пропускают пробелы, поэтому вам нужны только пробелы в формате перед буквенными символами или директивами %c, %[ и %n, которые не пропускают пробелы.

Так что для ваших целей вам нужна строка формата, например:

while(fscanf(filename,
         " (%3d%2d%2d%c ,%2d%2d%2d%c ) (%3d%2d%2d%c ,%2d%2d%2d%c )",
         &firstLonD, &firstLonM, &firstLonS, &firstLonC,
         &firstLatD, &firstLatM, &firstLatS, &firstLatC,
         &secLonD, &secLonM. &secLonS, &secLonC,
         &secLatD, &secLatM, &secLatS, &secLatC) == 16) {

Хотя, возможно, было бы также лучше прочитать отдельные координаты в цикле, а затем объединить их в пару:

while(fscanf(filename,
         " (%3d%2d%2d%c ,%2d%2d%2d%c )",
         &LonD, &LonM, &LonS, &LonC,
         &LatD, &LatM, &LatS, &LatC) == 8) {

Также может быть лучше прочитать широту / долготу как одно число, а затем разделить его на градусы / минуты / секунды с помощью div / mod на 100:

while(fscanf(file, " (%d%c ,%d%c )", &lonVal, &lonDir, &latVal, &latDir) == 4) {
    lonDeg = lonVal / 10000;
    lonMin = (lonVal % 10000) / 100;
    lonSec = lonVal % 100;

таким образом, вы можете справиться с долготой <100 градусов, не требуя начальных 0, чтобы они были ровно 7 цифрами ... </p>


Сканф и друзья в том, что они хотят читать вещи, разделенные пробелами, и им все равно, чтовид пробела это.Таким образом, ввод всего в одну строку только с пробелами (или табуляцией) - это то же самое, что и несколько строк.Это преднамеренная «особенность» работы scanf, поэтому, если вы действительно заботитесь о разнице между переводами строки и другими пробелами, scanf не является подходящим инструментом.

0 голосов
/ 20 февраля 2019

Лучше проектировать чтение строк из файла с помощью функции чтения прямой строки (например, fgets), а затем использовать синтаксический анализ строки для строки, считанной из файла с sscanf или подобным.scanf -семейные функции, как правило, не должны использоваться для непосредственного чтения из потоков, а только из строк.

Затем следует также проверить возвращаемое значение sscanf, чтобы убедиться, что каждое значение было отсканировано впредназначен для соответствующего типа.

char line[200];
while(fgets(line, 200, stdin))
{
    if(sscanf(line, "<format-string-here>", ...) != 16)
    {
        // handle error
    }
}
...