Извлечение числовых значений из строки и усреднение их - PullRequest
0 голосов
/ 03 марта 2020

У меня есть файл .txt, который содержит данные в этом формате:

xxxx: 0.9467,  
yyyy: 0.9489,  
zzzz: 0.78973,  
hhhh: 0.8874,  
yyyy: 0.64351,  
xxxx: 0.8743,

и так далее ...

Допустим, мой C Программа получает в качестве входных данных строку yyyy. Программа должна просто вернуть все экземпляры yyyy в файле .txt и среднее значение всех их числовых значений.

int main() {
    FILE *filePTR;
    char fileRow[100000];

    if (fopen_s(&filePTR, "file.txt", "r") == 0) {
        while (fgets(fileRow, sizeof fileRow, filePTR) != NULL) {
            if (strstr(fileRow, "yyyy") != NULL) { // Input parameter
                printf("%s", fileRow);
            }
        }
        fclose(filePTR);
        printf("\nEnd of the file.\n");
    } else {
        printf("ERROR! Impossible to read the file.");
    }
    return 0;
}

Это мой код прямо сейчас. Я не знаю, как:

  1. Изолировать числовые значения
  2. фактически преобразовать их в тип double
  3. усреднить их

Я прочитал кое-что о функции strtok (только для начала), но мне нужна помощь ...

1 Ответ

1 голос
/ 04 марта 2020

Вы начали с правильного пути и заслуживаете похвалы за использование fgets() для чтения полной строки из файла на каждой итерации, но ваш выбор strstr не гарантирует, что префикс, который вы ищете, найден в начале строки.

Кроме того, вы хотите избежать жесткого кодирования как строки поиска, так и файла, который нужно открыть. main() принимает аргументы через argc и argv, которые позволяют вам передавать информацию в вашу программу при запуске. См .: C11 Standard - §5.1.2.2.1 Запуск программы (p1) . Использование параметров устраняет необходимость в жестком кодировании значений, позволяя передать открываемое имя файла и префикс для поиска в качестве аргументов вашей программы. (что также избавляет от необходимости перекомпилировать ваш код просто для чтения из другого имени файла или поиска другой строки)

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

#include <stdio.h>
#include <string.h>

#define MAXC 1024   /* if you need a constant, #define one (or more) */

int main (int argc, char **argv) {

    char buf[MAXC] = "", *str = NULL;   /* buffer for line and ptr to search str */
    size_t n = 0, len = 0;              /* counter and search string length */
    double sum = 0;                     /* sum of matching lines */
    FILE *fp = NULL;                    /* file pointer */

    if (argc < 3) { /* validate 2 arguments given - filename, search_string */ 
        fprintf (stderr, "error: insufficient number of arguments\n"
                "usage: %s filename search_string\n", argv[0]);
        return 1;
    }

    if (!(fp = fopen (argv[1], "r"))) { /* open/validate file open for reading */
        perror ("fopen-filename");
        return 1;
    }
    str = argv[2];                      /* set pointer to search string */
    len = strlen (str);                 /* get length of search string */
    ...

На этом этапе в вашей программе вы открыли файл, переданный в качестве первого аргумента, и подтвердили, что он открыт для чтения через файловый поток. указатель fp. Вы передали префикс для поиска в качестве второго аргумента, присвоили его указателю str, получили длину префикса и сохранили в len.

Далее вы хотите прочитать каждая строка из вашего файла в buf, но вместо попытки сопоставить префикс с strstr(), вы можете использовать strncmp() с len, чтобы сравнить начало строки, прочитанной из вашего файла. Если префикс найден, вы можете использовать sscanf, чтобы проанализировать значение double из файла и добавить его к sum и увеличить число значений, хранящихся в n, например,

    while (fgets (buf, MAXC, fp)) {             /* read each line into buf */
        if (strncmp (buf, str, len) == 0) {     /* if prefix matches */
            double tmp;                         /* temporary double for parse */
            /* parse with scanf, discarding prefix with assignment suppression */
            if (sscanf (buf, "%*1023[^:]: %lf", &tmp) == 1) {
                sum += tmp;             /* add value to sum */
                n++;                    /* increment count of values */
            }
        }
    }

( примечание: над оператором подавления назначения для sscanf(), '*' позволяет считывать и отбрасывать префикс и ':' без необходимости сохранять префикс в вторая строка)

Осталось только проверить, содержатся ли значения в sum, проверив счетчик n и, если так, выведите среднее значение для префикса. Или, если n == 0 префикс не найден в файле, например:

    if (n)  /* if values found, output average */
        printf ("prefix '%s' avg: %.4f\n", str, sum / n);
    else    /* output not found */
        printf ("prefix '%s' -- not found in file.\n", str);
}

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

#include <stdio.h>
#include <string.h>

#define MAXC 1024   /* if you need a constant, #define one (or more) */

int main (int argc, char **argv) {

    char buf[MAXC] = "", *str = NULL;   /* buffer for line and ptr to search str */
    size_t n = 0, len = 0;              /* counter and search string length */
    double sum = 0;                     /* sum of matching lines */
    FILE *fp = NULL;                    /* file pointer */

    if (argc < 3) { /* validate 2 arguments given - filename, search_string */ 
        fprintf (stderr, "error: insufficient number of arguments\n"
                "usage: %s filename search_string\n", argv[0]);
        return 1;
    }

    if (!(fp = fopen (argv[1], "r"))) { /* open/validate file open for reading */
        perror ("fopen-filename");
        return 1;
    }
    str = argv[2];                      /* set pointer to search string */
    len = strlen (str);                 /* get length of search string */

    while (fgets (buf, MAXC, fp)) {             /* read each line into buf */
        if (strncmp (buf, str, len) == 0) {     /* if prefix matches */
            double tmp;                         /* temporary double for parse */
            /* parse with scanf, discarding prefix with assignment suppression */
            if (sscanf (buf, "%*1023[^:]: %lf", &tmp) == 1) {
                sum += tmp;             /* add value to sum */
                n++;                    /* increment count of values */
            }
        }
    }

    if (n)  /* if values found, output average */
        printf ("prefix '%s' avg: %.4f\n", str, sum / n);
    else    /* output not found */
        printf ("prefix '%s' -- not found in file.\n", str);
}

Пример использования / Вывод

Используя файл данных, хранящийся в dat/prefixdouble.txt, вы можете искать каждый префикс в файле и получить среднее значение, например,

$ ./bin/prefixaverage dat/prefixdouble.txt hhhh
prefix 'hhhh' avg: 0.8874

$ ./bin/prefixaverage dat/prefixdouble.txt xxxx
prefix 'xxxx' avg: 0.9105

$ ./bin/prefixaverage dat/prefixdouble.txt yyyy
prefix 'yyyy' avg: 0.7962

$ ./bin/prefixaverage dat/prefixdouble.txt zzzz
prefix 'zzzz' avg: 0.7897

$ ./bin/prefixaverage dat/prefixdouble.txt foo
prefix 'foo' -- not found in file.

Гораздо проще, чем перекомпилировать каждый раз, когда вы хотите найти другой префикс. Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.

...