C. Сохранение десятичного значения char в массиве не может читать/сохранять 8-битные символы

У меня есть вопрос, с которым, я надеюсь, вы мне поможете.

Я пытаюсь прочитать символы из файла, для которого я буду выполнять частотный анализ. Я решил, что самый простой способ для этого - иметь массив с индексом 0-255 и увеличивать соответствующий индекс (из десятичного значения чтения символов) на единицу каждый раз, когда этот символ читается. У меня проблема в том, что сохраняются только 7-битные символы. Ниже приведен код.

int frequency(FILE *freqfilep)
{    
    printf("frequency function called!\n");

    int start = 1;
    int *frqarray = calloc(256,sizeof(int));
    unsigned char tecken;

    FILE *fp;
    fp = fopen("freqfile.txt","r");

    if (fp == NULL) 
    {
        perror("Error in opening file");
        start = 0;
    }
    do
    {
        tecken = fgetc(fp);

        if (feof(fp))
        {
            start = 0;
        }
        else
        {
            frqarray[(int)tecken] ++;
        }
    }
    while (start != 0);

    printf("a%d\n", frqarray[97]);
    printf("b%d\n", frqarray[98]);
    printf("c%d\n", frqarray[99]);
    printf("1%d\n", frqarray[49]);
    printf("2%d\n", frqarray[50]);
    printf("3%d\n", frqarray[51]);
    printf("å%d\n", frqarray[134]);
    printf("ä%d\n", frqarray[132])
    printf("ö%d\n", frqarray[148]);

    fclose(fp);

    return 0;
}

Файл, который я читаю, содержит следующие символы:

aaa bbb ccc 111 222 333 ååå äää ööö

Итак, printf внизу моего кода должен сказать:

a3
b3
c3
13
23
33
å3
ä3
ö3

Но результат

a3
b3
c3
13
23
33
å0
ä0
ö0

Итак, я предполагаю, что есть какая-то проблема с чтением 8-битных символов, я немного просмотрел форум и нашел несколько относительно похожих сообщений, в которых был ответ, что мне нужно использовать такой буфер fread(&buffer, 256, 1, file);, но я м не уверен, как это реализовать.


person Byfjunarn    schedule 02.02.2016    source источник
comment
Вы уверены, что эти последние 3 набора символов не являются многобайтовыми символами?   -  person dbush    schedule 02.02.2016
comment
Посмотрите ЗДЕСЬ   -  person LPs    schedule 02.02.2016


Ответы (2)


Эти символы, скорее всего, являются не однобайтовыми символами с установленным старшим битом, а многобайтовыми символами.

Эти символы представлены следующими кодовыми точками UTF-8:

  • å: 0xc3 0xa5 (десятичное число 195 165)

  • ä: 0xc3 0xa4 (десятичное число 195 164)

  • ö: 0xc3 0xb6 (десятичное число 195 182)

Добавьте в свой код следующее:

printf("195 %d\n", frqarray[195]);
printf("165 %d\n", frqarray[165]);
printf("164 %d\n", frqarray[164]);
printf("182 %d\n", frqarray[182]);

И вы, вероятно, получите этот вывод:

195 9
165 3
164 3
182 3

РЕДАКТИРОВАТЬ:

Если вам нужно выполнить частотный анализ символов, используйте вместо этого fgetwc для чтения символов. Если вы ожидаете, что все символы будут в основном многоязычном наборе (Unicode символы U-0000 - U- FFFF) вы можете создать массив размером 65536 и вывести его. Если вы ожидаете символы за пределами этого диапазона, вы можете использовать другую схему.

person dbush    schedule 02.02.2016
comment
Он отлично работает с кодами UTF-8, которые вы мне дали. Оказывается, я использовал неправильные коды, так как использовал расширенную кодовую таблицу ASCII. Я буду помнить о fgetwc, если у меня возникнут какие-либо проблемы. Спасибо дбуш! - person Byfjunarn; 02.02.2016
comment
@Byfjunarn Рад, что смог помочь. Не стесняйтесь принять этот ответ, если он показался вам полезным. - person dbush; 02.02.2016

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

Это сводится к тому факту, что C char и особенно unsigned char в основном представляют собой байты, а не «символы», скажем, в смысле этого термина в Юникоде. Если файл, который вы читаете, закодирован в многобайтовой кодировке (весьма вероятно, UTF-8), то ваш fgetc() будет считывать отдельные байты этой кодировки и не будет декодировать их в значения кодовых точек. Кроме того, нет уверенности в том, что кодировка символов, используемая внутри вашей программы на C, совпадает с кодировкой файла.

Если вы хотите прочитать символьные данные, вам нужно правильно их декодировать. Если вы не хотите писать логику декодирования в самой программе, вы должны убедиться, что входной файл закодирован так, как ожидает ваша программа. Транскодер, такой как iconv, может помочь с этим, но вам нужно знать как текущую кодировку файла, так и кодировку, в которую вы хотите преобразовать.

person John Bollinger    schedule 02.02.2016