Неожиданный результат при подсчете букв в файле - PullRequest
0 голосов
/ 27 октября 2019

Итак, я писал программу для статического криптоанализа, когда столкнулся с необычным поведением.

Сначала я написал счетчик символов, и вот здесь возникает проблема.

У меня есть файл:

//alphabet.txt
abcdefghijklmnopqrstuvwxyz

и когда я попытался сосчитатьЧастота букв, получил интересный результат! (Не обращайте внимания на первую строку, это просто говорит, что если поток открыт) * ​​1008 *

D:\Workspaces\EclipseWS\StaticAnalysis\src>g++ main.cpp

D:\Workspaces\EclipseWS\StaticAnalysis\src>a.exe
1!
a       1
b       1
c       1
d       1
e       1
f       1
g       1
h       1
i       1
j       1
k       1
l       1
m       1
n       1
o       1
p       1
q       1
r       1
s       1
t       1
u       1
v       1
w       1
x       1
y       1
z       2

Как вы можете видеть, программа говорит, что 'z' появляется в тексте 2 раза, но это не так.

Теперь к техническим деталям.

Operating System: Windows 10 Enterprise LTSC
System Type: 64bit
C++ compiler: MinGW
alphabet.txt File encoding: ANSI

Код, я проанализировал файл с помощью:

#include <fstream>
#include <iostream>
#include <map>
#include <string>

using namespace std;

#define encrypted_fname "D:\\Workspaces\\EclipseWS\\StaticAnalysis\\src\\alphabet.txt"

void printMap(const map<char,int>& m){
    for (const auto& p : m){
        cout<<p.first<<'\t'<<p.second<<endl;
    }
}

int main(){
    ifstream ifs(encrypted_fname);
    cout << ifs.is_open() << "!\n";
    map<char,int> letterCount;

    char buffer;

    while(ifs){
        ifs >> buffer;
        letterCount[buffer]+=1;
    }

    printMap(letterCount);

}

Я попытался изменить кодировку файла на UTF-8

1!
»   1
¿   1
ï   1
a   1
b   1
c   1
d   1
e   1
f   1
g   1
h   1
i   1
j   1
k   1
l   1
m   1
n   1
o   1
p   1
q   1
r   1
s   1
t   1
u   1
v   1
w   1
x   1
y   1
z   2

.. Unicode с прямым порядком байтов \ unicode ..

1!
þ   1
ÿ   1
    28
a   1
b   1
c   1
d   1
e   1
f   1
g   1
h   1
i   1
j   1
k   1
l   1
m   1
n   1
o   1
p   1
q   1
r   1
s   1
t   1
u   1
v   1
w   1
x   1
y   1
z   1

Но, как вы можете видеть, вывод в каждом случае немного неубедительный!

Я могу предоставитьесли вам нужна дополнительная информация, просто скажите мне, как ее получить.

Мои основные вопросы: почему это происходит? У меня есть ошибка в коде? Как это исправить?

1 Ответ

0 голосов
/ 28 октября 2019
 while (1) {
        ifs >> buffer;
        if (! ifs) break;
        letterCount[buffer]+=1;
    } ;

должен это сделать. «ifs» не будет ложным, если последнее чтение было успешным, только если попытка прочитать за его пределами, это будет оценено как «ложное». Но в этот момент буква «z», являющаяся последней буквой, ничем не перезаписывается и учитывается дважды.

Этот синтаксис для чтения файлов был попыткой в ​​то время, когда он был создан, чтобы иметь "хороший интерфейс" для чтения текста. Я бы сказал, что он не может превзойти вызов read(ifs, &buffer, 1) с файлом.

Ваши другие странные результаты связаны с тем, что вы всегда читаете байты из файла и никогда не пытаетесь декодировать эти байты в текст - так что обамаркер BOM и дополнительный байт для 2-байтовой кодировки, которую вы называете «большим порядком байтов в юникоде» (правильное имя будет «utf-16 big endian»), все его байты считаются как символы.

...