Проверьте, все ли буквы алфавита появляются в файле без повторов - PullRequest
0 голосов
/ 05 февраля 2019

Я пишу программу, которая должна прочитать файл CSV и проверить, чтобы все буквы в алфавите появлялись по одному разу на каждой стороне запятой.Файл будет выглядеть примерно так:

a,x
b,j
c,g
d,l
e,s
f,r
g,u
h,z
i,w
j,c
k,e
l,a
m,v

, но всего будет 26 строк.Какой самый эффективный способ проверить, что на каждой стороне есть все 26 букв без повторов?

Ответы [ 2 ]

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

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

ОткрытьВаш файл (или чтение stdin)

Прежде чем вы сможете что-либо сделать с содержимым вашего файла, вам необходимо открыть файл для чтения.Для чтения форматированного ввода вы обычно будете использовать функции, которые читают и пишут из файлового потока, используя указатель потока FILE * (в отличие от низкоуровневого file-descriptor file interface).Чтобы открыть файл, вам нужно позвонить fopen и , чтобы проверить return , чтобы подтвердить успешное открытие.

Не вводите жесткий кодимена файлов или номера в вашей программе.Ваша программа принимает аргументы, либо передайте имя файла для открытия в качестве аргумента, либо запросите ввод имени файла.Вы можете повысить гибкость своей программы, взяв имя файла для чтения в качестве аргумента или прочитав из stdin по умолчанию, если аргумент не предоставлен (как это делают большинство утилит Linux).Поскольку stdin является файловым потоком, вы можете просто назначить его указателю FILE*, если не открываете имя файла, указанное в качестве аргумента.Например:

    FILE *fp = NULL;

    if (argc > 1)               /* if one argument provided */
        fopen (argv[1], "r");   /* open file with name from argument */
    else
        fp = stdin;             /* set fp to stdin */

    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }

, который можно сократить с помощью оператора троичный , например:

    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

Чтение ваших данных

С открытым потоком файлов и подтверждением 1037 * теперь вы можете читать свои данные из файла.Хотя вы можете читать с fscanf, вы ограничены в информации, которую он предоставляет в случае, если два значения не читаются.Кроме того, чтение с помощью семейства функций scanf сопряжено с трудностями, связанными с тем, какие символы остаются во входном потоке файлов в зависимости от используемых спецификаторов преобразования и от того, было ли преобразование выполнено успешно или нет.Тем не менее, простой подход, который проверяет два преобразования, был выполнен в соответствии с вашей format-string , что позволит вам прочитать ваш файл, например,

    char c1, c2;    /* characters from each line */
    int freq1[MAXC] = {0}, freq2[MAXC] = {0};   /* frequency arrays */
    ...
    while (fscanf (fp, " %c, %c", &c1, &c2) == 2)   /* read all chars */
        if (c1 > 0 || c2 > 0)   /* validate ASCII values */
            /* increment element in each */
            freq1[(unsigned char)c1]++, freq2[(unsigned char)c2]++;

(недостатком является любое изменение формата наодна строка может оставить вас с ненужными символами, и если произойдет менее двух преобразований, ваш цикл чтения прекратится, несмотря на то, что действительные данные остаются непрочитанными)

Лучшим подходом является чтение строки за раз с линейно-ориентированная функция ввода, такая как fgets или POSIX getline.При таком подходе вы одновременно используете строку данных, а затем анализируете необходимую информацию из сохраненной строки.Преимущества являются значительными.У вас есть независимая проверка самого чтения, а затем вы найдете нужные значения в строке.Если ваш формат отличается и вы анализируете меньше, чем необходимые значения из строки, у вас есть возможность просто пропустить эту строку и перейти к следующей.Кроме того, то, что остается в потоке входного файла, не зависит от используемых спецификаторов преобразования.

Пример с fgets и sscanf, делающими то же самое:

    char c1, c2,            /* characters from each line */
        buf[MAXC] = "";     /* buffer to hold each line */
    ...
    while (fgets (buf, MAXC, fp))   /* read all chars */
        if (sscanf (buf, " %c, %c", &c1, &c2) == 2) { /* parse values */
            if (c1 > 0 || c2 > 0)   /* validate ASCII values */
                /* increment element in each */
                freq1[(unsigned char)c1]++, freq2[(unsigned char)c2]++;
        }
        else
            fputs ("error: in line format.\n", stderr);

Обработка частоты символов

Если вы обращали внимание на чтение данных из файла, вы заметите, что пара частотных массивов увеличивалась при каждом чтениисимволы freq1 и freq2.Как упоминалось в моих комментариях выше, вы начинаете с массива адекватного размера int для хранения набора символов ASCII.Массивы инициализируются нулями.Когда вы читаете символ из каждого столбца, вы просто увеличиваете значение на:

        if (c1 > 0 || c2 > 0)   /* validate ASCII values */
            /* increment each element */
            freq1[(unsigned char)c1]++, freq2[(unsigned char)c2]++; 

Например, значение ASCII для 'a' равно 97 (см. Таблица ASCII и описание ).Поэтому, если вы читаете 'a' и увеличиваете

    freq1['a']++;

, что аналогично увеличению:

    freq1[97]++;

Когда вы закончите цикл чтения, вам просто нужно будет выполнить итерациюваши частотные массивы от 'a' до 'z' и количество раз, когда соответствующий символ, появившийся в вашем файле, будет записан в ваш массив.Тогда вы можете использовать данные по своему усмотрению.

Вывод результатов

Самый простой способ вывести результаты column1 / column2 - просто вывести количество вхождений для каждого символа.Например:

    for (int i = 'a'; i <= 'z'; i++)    /* loop over 'a' to 'z' */
        printf (" %c:  %d, %d\n", i, freq1[i], freq2[i]);

, который будет производить вывод, похожий на:

$ ./bin/freq_dual_col2 <dat/char2col.txt
lowercase occurrence:

 a:  1, 1
 b:  1, 0
 c:  1, 1
 d:  1, 0
 e:  1, 1
 f:  1, 0
 ...

Если вы хотите получить более подробный текст и обратите внимание, появляются ли символы "none" или 1 или если персонаж был дублирован "dupe", вы можете использовать несколько дополнительных проверок, например,

    for (int i = 'a'; i <= 'z'; i++) {  /* loop over 'a' to 'z' */
        if (freq1[i] == 1)              /* check col 1 chars */
            printf ("  %c , ", i);
        else if (!freq1[i])
            fputs ("none, ", stdout);
        else
            fputs ("dupe, ", stdout);
        if (freq2[i] == 1)              /* check col 2 chars */
            printf ("  %c\n", i);
        else if (!freq2[i])
            fputs ("none\n", stdout);
        else
            fputs ("dupe\n", stdout);
    }

, которые будут производить вывод в виде:

$ ./bin/freq_single_dual_col <dat/char2col.txt
lowercase single occurrence, none or dupe:

  a ,   a
  b , none
  c ,   c
  d , none
  e ,   e
  f , none
  ...

В целом, ваш минимальныйПример использования fscanf для чтения может быть похож на:

#include <stdio.h>
#include <limits.h>

#define MAXC UCHAR_MAX+1

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

    char c1, c2;    /* characters from each line */
    int freq1[MAXC] = {0}, freq2[MAXC] = {0};   /* frequency arrays */
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }

    while (fscanf (fp, " %c,%c", &c1, &c2) == 2)    /* read all chars */
        if (c1 > 0 || c2 > 0)   /* validate ASCII values */
            /* increment each element */
            freq1[(unsigned char)c1]++, freq2[(unsigned char)c2]++;   

    if (fp != stdin) fclose (fp);       /* close file if not stdin */

    puts ("lowercase occurrence:\n");
    for (int i = 'a'; i <= 'z'; i++)    /* loop over 'a' to 'z' */
        printf (" %c:  %d, %d\n", i, freq1[i], freq2[i]);

    return 0;
}

Пример использования fgets и sscanf будет похож на:

#include <stdio.h>
#include <limits.h>

#define MAXC UCHAR_MAX+1

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

    char c1, c2,            /* characters from each line */
        buf[MAXC] = "";     /* buffer to hold each line */
    int freq1[MAXC] = {0}, freq2[MAXC] = {0};   /* frequency arrays */
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }

    while (fgets (buf, MAXC, fp))   /* read each line */
        if (sscanf (buf, " %c, %c", &c1, &c2) == 2) { /* parse values */
            if (c1 > 0 || c2 > 0)   /* validate ASCII values */
                /* increment each element */
                freq1[(unsigned char)c1]++, freq2[(unsigned char)c2]++;   
        }
        else
            fputs ("error: in line format.\n", stderr);

    if (fp != stdin) fclose (fp);       /* close file if not stdin */

    puts ("lowercase occurrence:\n");
    for (int i = 'a'; i <= 'z'; i++)    /* loop over 'a' to 'z' */
        printf (" %c:  %d, %d\n", i, freq1[i], freq2[i]);

    return 0;
}

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

Просмотрите все и дайте мне знать, если у вас есть дополнительные вопросы.

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

Добавьте все столбцы в наборы и убедитесь, что наборы имеют одинаковый размер строк файла.

  • помните, что наборы игнорируют дубликаты
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...