Кириллический ввод-вывод, c++

Еще в процессе обучения. Я сделал небольшую программу, которая будет:

  1. Создайте файл с пользовательскими входами
  2. Прочитать файл
  3. Заполните структуру из файла, отсортируйте и создайте новый файл "имя sorted.txt"

это мои 3 случая. Проблема возникает, когда я ввожу кириллический текст и пытаюсь заполнить структуру, отсортировать и создать новый файл (используя вариант 3:...). Структура не заполняется, если я правильно провел тест. Но он правильно создает и читает файл (случай 1,2)

Программа делает все правильно, если я использую только латиницу. Мой код, если ниже любая помощь приветствуется...

#include "stdafx.h"
#include "iostream"
#include <fstream>
#include "string"
#include <sys/stat.h>
#include<clocale>
#include <Windows.h>
using namespace std;

#define  MAX 10000// max number of students per list

//void sortStruct(); sorting structure
//void swap(studentStruct , studentStruct ); helping with sort function
//void readFile (string );reading a .txt file (ex. Saved list)
//void printStruct(); printing the struct
//void fillStruct(string ); filling a struct from a chosen file, helpin with a sort
//void calculateGrade(ofstream , int ); calcuating average grade, under witch we sort
//void writeToFile(ofstream , string ,float ); writing to a .txt file
//void printMenu(); printing a menu to chose from

//for sorting the list
struct studentStruct{
string name;
float grade;
}student[MAX];


static void printMenu()
{
    //setlocale(LC_ALL, "Russian");
    cout<<"MENU"<<endl<<endl;
    cout<<"1. Добавить новые записи в файл или создать новый файл"<<endl;
    cout<<"2. Распечатайте файл на терминал"<<endl;
    cout<<"3. Сделать отсортированный версию текстового файла"<<endl;
    cout<<"4. Bыход"<<endl<<endl;
    cout<<"Выберите (цифры) :   ";
}
inline bool exists_test (const std::string& name) {
    ifstream f(name.c_str());
    if (f.good()) {
        f.close();
        return true;
    } else {
        f.close();
        return false;
    }   
}
void writeToFile(ofstream &outputFile, string name,float grade)
{   

    outputFile<<name<<" "<<grade<<endl;

cout << "Готово!\n";
}

void calculateGrade(ofstream &outputFile, int numProf)
{
    float sum;
    string name,last;

    cout<<endl<<endl;
    cout<<"Введите имя студента : ";
    cin.sync();
    getline(cin,name);
    cout<<endl;
    for(int i=0; i<numProf;i++)
    {
        cout<<"Введите "<<i+1<<". оценку (цифры) : ";
        cin>>sum;
        sum+=sum;
    }
    float grade=sum/numProf; 

    writeToFile(outputFile, name,grade);
}

static void fillStruct(string FileName)
{
    ifstream rdFile;    //Input Object
    bool i;
    i=exists_test(FileName);
    if(i=true)cout<<"IMA";
    rdFile.open(FileName);

    for(int i=0; i<MAX;i++)
    {
        rdFile>>student[i].name;
        rdFile>>student[i].grade;
    }

    rdFile.close();

}
static void printStruct()
{
for(int i=0;i<MAX;i++){
        if(student[i].grade!=0)
        cout<<student[i].name<<" "<<student[i].grade<<endl;}
cout<<"Готово!"<<endl;
}


static void readFile (string FileName)
{
    ifstream rdFile;    //Input Object
    rdFile.open(FileName);
    cout<<endl;
    string n;
    if (!rdFile)
    {
        cout<<"File could not be open...";exit(1);
    }
    else  
    {   
        while (rdFile && getline(rdFile, n))
        {
            if (n.length() == 0)continue;
            cout<<n<<endl;
        }
    }
    rdFile.close();
    cout<<endl<<"Готово!"<<endl;
    system("PAUSE");
}


void swap(studentStruct &x, studentStruct & y)
{
    studentStruct temp;
    temp = x;
    x = y;
    y = temp;
}

static void sortStruct()
{
    for (int i = 1; i < MAX; i++)
      {
          for (int j = 0; j < MAX-i; j++)
        {
            if (student[j].grade < student[j+1].grade)
              {
                  swap(student[j].grade, student[j+1].grade);
                  swap(student[j].name, student[j+1].name);
          }
        }    
       }
}

static void writeStructToFile(string outputFile)
{
    ofstream rdFile;
    rdFile.open(outputFile);
    for(int i=0; i<MAX; i++)
    {
        if(student[i].grade!=0)
        {
            rdFile<<student[i].name<<" "<<student[i].grade<<endl;
        }
    }
    rdFile.close();

    cout<<"Готово!"<<endl;
}

int _tmain(int argc, _TCHAR* argv[])
{
    bool check;
    int flag=0,numProf,newEntreies;
    string FileName,tempName,n;
    ofstream outputFile;
    ifstream nnn;
    SetConsoleCP(1251);
    SetConsoleOutputCP(1251);

    do 
    {
        system("CLS");
        printMenu();
        cin>>flag;

        //while(flag!=1||flag!=2||flag!=3||flag!=4){
            //system("CLS");        
            //printMenu();
            //cin>>flag;}

        switch(flag)
        {
        case 1 : 
            if(FileName=="exit") {cout<<"Program will exit now..."<<endl; flag=-2;break;}
            else if(FileName=="menu")break;
            cout<<"Выберите имя для нового текстового файла (буквы и цифры):  ";
            cin.sync();
            getline(cin,FileName);
            cout<<"Введите число профессоров (цифры):  ";
            cin>>numProf;
            cout<<"Введите число студентов (цифры) :  ";
            cin>>newEntreies;
            tempName=FileName+".txt";
            check=exists_test(tempName);
            if(check==true)
                outputFile.open(tempName, std::ios_base::app); 
            else
                outputFile.open(tempName);
            if(outputFile.fail()) 
            { //if opening fails then end program
                 cout << "Input file opening failed." << endl;
                 exit(1);
            } //exit function from cstdlib library
            system("CLS");
            for(int i=0; i<newEntreies;i++)
            {
                cout<<FileName<<" "<<numProf<<" "<<newEntreies<<endl<<endl;
                cout<<"Добавление "<<i+1<<". студента...";
                calculateGrade(outputFile,numProf);
                system("CLS");
            }
                outputFile.close();
                cout<<"Нажмите любую клавишу для продолжения..."<<endl;
            break;
        case 2 :
            if(FileName=="exit") {cout<<"Program will exit now..."<<endl;flag=-2;break;}
            else if(FileName=="menu")break;
            cout<<"Введите имя файла:  ";
            cin.sync();
            getline(cin,FileName);
            system("cls");
            cout<<"Чтение из файла "<<FileName<<".txt"<<endl;

            tempName=FileName+".txt";
            readFile(tempName);
            cout<<"Нажмите любую клавишу для продолжения..."<<endl;
            break;
        case 3 : 
            if(FileName=="exit") {flag=-2;break;}
            else if(FileName=="menu")break;
            system("CLS");
            cout<<endl<<"Изготовление отсортированного файла..."<<endl<<endl;
            cout<<"Выберите файл .txt(буквы и цифры): ";
            cin.sync();
            getline(cin,FileName);
            tempName=FileName+" SORTED.txt";
            fillStruct(FileName+".txt");
            sortStruct();
            writeStructToFile(tempName);
            cout<<endl<<endl<<"Отсортировано версия "<<FileName<<" Готово!"<<endl<<endl;
            cout<<"Нажмите любую клавишу для продолжения..."<<endl;
            system("PAUSE");
            break;
        case 4: cout<< "Program will exit now..."<<endl; flag=-2;break;
        default :cout<<"Program will exit now..."<<endl;flag=-2;break;

        }

    }while(flag!=-2);

    system ("PAUSE");
    return 0;
}

person user3350597    schedule 17.03.2015    source источник
comment
1. Вам необходимо предоставить небольшой пример, демонстрирующий проблему. 2. std::string, основанный на char, предназначен только для хранения текста ASCII. Вам нужно std::wstring.   -  person dandan78    schedule 17.03.2015
comment
wstring — это хороший шаг вперед, но консоль Windows, как известно, сложна для использования с Unicode.   -  person MSalters    schedule 17.03.2015
comment
@dandan78 русский в windows в ASCII, так что с ним все в порядке   -  person Slava    schedule 17.03.2015
comment
Вам нужно быть более конкретным, что вы подразумеваете под Struct не заполняется.   -  person Slava    schedule 17.03.2015
comment
С латиницей у вас программа тоже не может все правильно сделать, по крайней мере у вас сортировка нарушена - вы меняете местами оценки вместо целых структур   -  person Slava    schedule 17.03.2015
comment
когда я использую fillStruct(), чтобы заполнить свою структуру из файла .txt, чтобы я мог отсортировать ее и создать отсортированный файл .txt, а затем попытаться выполнить printStruct(), я получаю черный экран, а также, если я пытаюсь отсортировать его и сделайте отсортированный файл .txt, он просто пустой.   -  person user3350597    schedule 17.03.2015
comment
ваш fillStruct() пытается безоговорочно прочитать 10000 записей, почему вы не используете тот же шаблон, что и в readFile()?   -  person Slava    schedule 17.03.2015
comment
@Слава, ты прав, я просто сортирую оценки ... нужно это исправить   -  person user3350597    schedule 17.03.2015
comment
@user3350597 user3350597 еще один пример, почему using namespace std; злой   -  person Slava    schedule 17.03.2015
comment
@Слава, просто я пытаюсь писать по-другому... это процесс обучения   -  person user3350597    schedule 17.03.2015
comment
@Слава, да, я знаю, но это немного быстрее, чем каждый раз, когда std::cout,cin и т. д.   -  person user3350597    schedule 17.03.2015
comment
Начните с 8-строчной программы, читая строку и записывая ее обратно. Вы можете сделать это правильно?   -  person n. 1.8e9-where's-my-share m.    schedule 17.03.2015
comment
@user3350597 user3350597, учитывая, что время, которое вы потратили на отладку своего сохранения, не вводя std::cout, является иллюзией.   -  person Slava    schedule 17.03.2015
comment
@nm да, я могу это сделать, у меня есть функции, которые это делают. Я правильно заполняю оба моих файла .txt, открываю и закрываю, и когда я не использую кириллицу, все работает. Написано, наверное, плохо, но я тренируюсь.   -  person user3350597    schedule 17.03.2015
comment
@Слава, я знаю, что мой профессор говорит то же самое... Я буду уделять этому больше внимания.   -  person user3350597    schedule 17.03.2015
comment
@Слава: русский язык в Windows находится в ASCII - эта строка не имеет никакого никакого смысла. ASCII — это 7-битная кодировка, которая определенно не включает кириллицу.   -  person DevSolar    schedule 17.03.2015
comment
когда я не пользуюсь кириллицей и толку от этого будет? Идея состоит в том, чтобы проверить, что вы можете сделать с кириллицей, а не без нее. Ваша 8-строчная программа работает с кириллическими символами?   -  person n. 1.8e9-where's-my-share m.    schedule 17.03.2015
comment
@DevSolar, это вопрос терминологии. Допустим, это расширение ASCII, которое умещается в 8 бит, поэтому работает с std::string   -  person Slava    schedule 17.03.2015
comment
@n.m да, я отредактирую свой код   -  person user3350597    schedule 17.03.2015
comment
@Slava: Терминология важна, когда речь идет о кодировках. Расширение ASCII, которое умещается в 8 бит, все еще может быть ISO-8859-5, KOI-8R, KOI-8U или чем-то еще. И вы действительно ожидаете, что компилятор автоматически определит источник OP?   -  person DevSolar    schedule 17.03.2015
comment
@DevSolar MS Windows использует (или использовала до Unicode) 2 кодировки для кириллицы: CP866, пришедшую из времени DOS (которая по-прежнему используется в консоли Windows по умолчанию), и CP1251 для собственных приложений Windows. KOI-8 в основном используется на платформах *nix. Кириллица — это довольно большой беспорядок на IBM PC.   -  person Slava    schedule 17.03.2015


Ответы (1)


Не особо смотрите на код вашего примера — слишком длинный, слишком плохо отформатированный, слишком плохо (совсем не) прокомментированный.

  • В какой кодировке исходный файл? UTF-8? (Что я настоятельно рекомендую, если только вы не дойдете до конца и не будете использовать ASCII-7 с побегами.) Или это ISO-8859-5? Кои-8р? Что-то совсем другое?
  • Вы сообщили об этом своему компилятору?

Только очень простой набор инструкций (в основном ASCII-7 без $, @ и обратной кавычки) фактически определен стандартом. Все остальное интерпретируется компилятором в зависимости от реализации. Либо вам нужно явно договориться с вашим компилятором о вашей исходной кодировке, либо вам нужно использовать шестнадцатеричные/октовые escape-последовательности, чтобы сохранить ваш исходный ASCII-7 и принудительно применить определенную кодировку вручную.

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

  • Ваш терминал должен иметь шрифт с соответствующими кириллическими глифами.
  • Поскольку вы используете std::cout, вы должны установить что-то вроде setlocale( LC_ALL, "ru_RU.UTF-8" ) или любую другую локаль UTF-8, если она поддерживается вашей системой (и предполагая, что ваши литералы используют эту кодировку). "Русский" как локаль вряд ли урежет...

При всем при этом std::string и UTF-8 представляют собой хрупкую смесь. Слишком легко забыть, что length() не дает количество глифов, substr() может привести к недопустимым последовательностям байтов, toupper() на самом деле не работает для всего, и многие другие подобные ловушки. Я рекомендую ICU, который предоставляет icu::UnicodeString, который "знает" обо всем этом.

person DevSolar    schedule 17.03.2015
comment
При всем при этом std::string и UTF-8 представляют собой хрупкую смесь. Я почти уверен, что он не использует UTF-8. - person Slava; 17.03.2015
comment
@Slava: Все к худшему, потому что UTF-8 и UTF-16 в основном являются единственными разумными вариантами. сегодня. - person DevSolar; 17.03.2015
comment
Я согласен, к сожалению, кириллические кодировки имеют довольно долгую и довольно запутанную историю на IBM PC, и привычки не умирают. - person Slava; 17.03.2015
comment
@Слава: Вот почему я стараюсь избавиться от этих старых привычек и не принимаю 8-битные работы для себя. - person DevSolar; 17.03.2015
comment
@Слава Не намного грязнее, чем китайский, или японский, или иврит, или арабский, или тайский, или что-то еще. - person n. 1.8e9-where's-my-share m.; 17.03.2015