Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[C++] Czytanie pliku od początku i pomijanie białych znaków

Ostatnio zmodyfikowano 2014-05-23 20:51
Autor Wiadomość
Phronux
Temat założony przez niniejszego użytkownika
[C++] Czytanie pliku od początku i pomijanie białych znaków
» 2014-05-23 10:51:38
Mój pierwszy post, więc witam wszystkich!

Mam mały problem z dociągnięciem do końca programu używającego szyfru Vigenere'a. Całość jest już praktycznie ukończona, ale od wczoraj zmagam się z dwoma małymi problemami, których za nic nie mogę naprawić. Najpierw kod:
C/C++
/*Szyfr Vigenere'a*/

#include <iostream>
#include <fstream>
#include <string>
#include <cctype>

#define EXIT_SUCCES 0;

bool is_empt( std::ifstream & );
void show_menu();
void szyfrowanie();
void deszyfrowanie();

bool is_empt( std::ifstream & pFile ) // funkcja sprawdzajaca czy plik jest pusty
{
    return pFile.peek() == std::ifstream::traits_type::eof();
}

void szyfrowanie()
{
    using namespace std;
   
    string filename_toCipher;
    ifstream inFile;
    cout << "Podaj nazwe pliku z tekstem jawnym: ";
    cin.clear();
    cin.ignore( numeric_limits < streamsize >::max(), '\n' );
    getline( cin, filename_toCipher ); // otwieranie pliku z tekstem jawnym
    inFile.open( filename_toCipher );
   
    if( !inFile.is_open() ) // gdy nie ma takiego pliku
    {
        cout << endl << "Otwarcie pliku nie powiodlo sie. Powrot do menu glownego." << endl;
        show_menu();
    }
   
    else if( is_empt( inFile ) ) // gdy plik jest pusty
    {
        cout << endl << "Plik jest pusty. Powrot do menu glownego." << endl;
        show_menu();
    }
   
    string filename_pass;
    ifstream fin;
    cout << "Podaj nazwe pliku z haslem: ";
    getline( cin, filename_pass ); // otwieranie pliku z haslem
    fin.open( filename_pass );
   
    if( !fin.is_open() ) // gdy nie ma takiego pliku
    {
        cout << "Otwarcie pliku nie powiodlo sie. Powrot do menu glownego." << endl;
        show_menu();
    }
   
    ofstream outFile; // jesli poprzednie pliki udalo sie otworzyc, tworzony zostaje plik wynikowy
    outFile.open( "encrypted.txt" );
   
    char znak, znak_haslo;
   
    while( !inFile.eof() ) // szyfrowanie
    {
        inFile >> znak;
        if( islower( znak ) ) // zamiana malego znaku na duzy
             znak = toupper( znak );
       
        fin >> znak_haslo;
        if( islower( znak_haslo ) ) // zamiana malego znaku na duzy
             znak_haslo = toupper( znak_haslo );
       
        znak =( znak + znak_haslo ) % 26 + 'A';
        outFile << znak;
    }
   
    cout << "Tekst zostal pomyslnie zaszyfrowany!\nWynik szyfrowania znajduje sie w pliku encrypted.txt" << endl << endl;
   
    outFile.close();
   
    show_menu();
}

void deszyfrowanie()
{
    using namespace std;
   
    string filename_toDeCipher;
    ifstream inFile;
    cout << "Podaj nazwe pliku z tekstem zaszyfrowanym: ";
    cin.clear();
    cin.ignore( numeric_limits < streamsize >::max(), '\n' );
    getline( cin, filename_toDeCipher ); // otwieranie pliku z tekstem zaszyfrowanym
    inFile.open( filename_toDeCipher );
   
    if( !inFile.is_open() ) // gdy nie ma takiego pliku
    {
        cout << endl << "Otwarcie pliku nie powiodlo sie. Powrot do menu glownego." << endl;
        show_menu();
    }
   
    else if( is_empt( inFile ) ) // gdy plik jest pusty
    {
        cout << endl << "Plik jest pusty. Powrot do menu glownego." << endl;
        show_menu();
    }
   
    string filename_pass;
    ifstream fin;
    cout << "Podaj nazwe pliku z haslem: ";
    getline( cin, filename_pass ); // otwieranie pliku z haslem
    fin.open( filename_pass );
   
    if( !fin.is_open() ) // gdy nie ma takiego pliku
    {
        cout << "Otwarcie pliku nie powiodlo sie. Powrot do menu glownego." << endl;
        show_menu();
    }
   
    ofstream outFile; // jesli poprzednie pliki udalo sie otworzyc, tworzony zostaje plik wynikowy
    outFile.open( "decrypted.txt" );
   
    char znak, znak_haslo;
   
    do // deszyfrowanie
    {
        inFile >> znak;
        if( islower( znak ) ) // zamiana malego znaku na duzy
             znak = toupper( znak );
       
        fin >> znak_haslo;
        if( islower( znak_haslo ) ) // zamiana malego znaku na duzy
             znak_haslo = toupper( znak_haslo );
       
        znak -= 65;
        znak_haslo =( 26 - znak_haslo ) % 26 + 65;
       
        znak =( znak + znak_haslo ) % 26 + 'A';
        outFile << znak;
    } while( !inFile.eof() );
   
    cout << "Tekst zostal pomyslnie rozszyfrowany!\nWynik szyfrowania znajduje sie w pliku decrypted.txt" << endl << endl;
   
    outFile.close();
   
    show_menu();
}

void show_menu()
{
    std::cout << "[1] Szyfrowanie" << std::endl;
    std::cout << "[2] Deszyfrowanie" << std::endl;
    std::cout << "[3] Wyjscie z programu" << std::endl;
    std::cout << "Wybor: _\b";
   
    int * wybor = new int;
   
    std::cin >> * wybor;
   
    switch( * wybor ) {
    case 1: {
            std::cout << "Wybrano funkcje szyfrujaca." << std::endl;
            szyfrowanie();
            break;
        }
    case 2: {
            std::cout << "Wybrano funkcje deszyfrujaca." << std::endl;
            deszyfrowanie();
            break;
        }
    case 3: {
            std::exit( EXIT_SUCCESS );
        }
        default: {
            std::cout << "Dokonano blednego wyboru. Prosze wybrac odpowiednia opcje." << std::endl;
            show_menu();
        }
    }
    delete wybor;
}

int main()
{
    using namespace std;
    cout << "Witaj w programie obslugujacym szyfr Vigenere\'a." << endl;
    show_menu();
   
    return EXIT_SUCCES;
}

1) Jeśli hasło jest dłuższe od kodu szyfrowanego to powinno być wczytywane od początku. I nie mogę dojść do tego jak to zrobić.
Próbowałem takie wstawienie do pętli:
C/C++
if( fin.eof() )
{
    fin.clear();
    fin.seekg( 0, ios_base::beg );
}

Ale nie działa.

2) Możliwe, że pierwszy problem jest pośrednio związany z drugim. Otóż, chciałbym aby w pliku z tekstem do zaszyfrowania (bądź odszyfrowania) pomijane były białe znaki. Próbowałem:
C/C++
inFile >> skipws >> znak;
oraz
C/C++
znak = inFile.get();

Ale obie opcje nie poskutkowały.

3) A, jeszcze jedna sprawa, choć najkrótsza i pewnie związana z pytaniem drugim. Pętla wczytuje (i szyfruje bądź deszyfruje) o jeden znak więcej niż jest w tekście. Jest to jakiś losowy znak, nie do końca wiem skąd się bierze. Więc jak szyfruje słowo TEKST hasłem TAJNY to powstaje mi METFRP zamiast METFR.

Za pomoc serdecznie dziękuję!
P-110723
pekfos
» 2014-05-23 12:47:05
1. Wczytaj hasło raz.
2. isspace()
3. Nie sprawdzasz, czy plik się skończył.

C/C++
#define EXIT_SUCCES 0;
Tu średnika nie może być. I dlaczego nie użyjesz samego 0, albo EXIT_SUCCESS..?
P-110726
Phronux
Temat założony przez niniejszego użytkownika
» 2014-05-23 18:05:02
O dziwo, wszystko udało mi się naprawić, poza jednym...
Wczytuję teraz od razu cały tekst i całe hasło do odpowiednich stringów, by to na nich operować.
Robię to w następujący sposób:

C/C++
string caly_tekst { };
while( getline( inFile, caly_tekst ) ) { } // petla wczytujaca tekst jawny do tablicy
caly_tekst.erase( std::_Remove_if( caly_tekst.begin(), caly_tekst.end(), isspace ), caly_tekst.end() ); // usuwanie bialych znakow

Jednakowoż, nie wiedzieć dlaczego, wczytuje cały plik POZA pierwszym znakiem. Wiecie dlaczego?
// Poprawka, nie wczytuje całego pliku, a tylko ostatni wiersz, ale wciąż bez pierwszego znaku.

Swoją drogą, te EXIT_SUCCESS robię tylko i wyłącznie by później w innym IDE to działało i dla własnej wygody, bo tak lubię. ;)
P-110747
Monika90
» 2014-05-23 18:23:16
std::_Remove_if? W C++ nie ma czegoś takiego.

C/C++
while( getline( inFile, caly_tekst ) ) { }
moim zdaniem jeżeli plik konćzy się znakiem '\n', to po wyjsciu z tej pętli caly_tekst jest pusty
P-110748
Phronux
Temat założony przez niniejszego użytkownika
» 2014-05-23 18:34:45
Albo:

std::remove_if

Nawet lepiej, choć dla mojego kompilatora (VS13) to żadna różnica.

Swoją drogą, udało mi się w końcu, lepiej było użyć np. inFile.get();

Tylko teraz jakoś źle wczytuje hasło w szyfrowaniu... muszę jeszcze posiedzieć.

P-110749
Phronux
Temat założony przez niniejszego użytkownika
» 2014-05-23 20:51:14
Nie wiem czy kogoś to może zainteresować, ale dla ludzi szukających w Googlu szyfru Vigenere'a w C++ wstawiam tutaj ostateczny, działający kod.
Temat jednocześnie zamykam.

C/C++
/*Szyfr Vigenere'a*/

#include <iostream>
#include <fstream>
#include <string>
#include <cctype>
#include <algorithm>

#define EXIT_SUCCESS 0

bool is_empt( std::ifstream & );
void encryption();
void decipherment();
void show_menu();

bool is_empt( std::ifstream & pFile ) // funkcja sprawdzajaca czy plik jest pusty
{
    return pFile.peek() == std::ifstream::traits_type::eof();
}

void encryption()
{
    using std::cout;
    using std::string;
    using std::ifstream;
    using std::cin;
    using std::endl;
    using std::getline;
    using std::ofstream;
   
    string filename_toCipher;
    ifstream inFile;
    cout << "Podaj nazwe pliku z tekstem jawnym: ";
    cin.clear();
    cin.ignore( std::numeric_limits < std::streamsize >::max(), '\n' );
    getline( cin, filename_toCipher ); // otwieranie pliku z tekstem jawnym
    inFile.open( filename_toCipher );
   
    if( !inFile.is_open() ) // gdy nie ma takiego pliku
    {
        cout << endl << "Otwarcie pliku nie powiodlo sie. Powrot do menu glownego." << endl << endl;
        show_menu();
    }
    else if( is_empt( inFile ) ) // gdy plik jest pusty
    {
        cout << endl << "Plik jest pusty. Powrot do menu glownego." << endl << endl;
        show_menu();
    }
   
    string filename_pass;
    ifstream fin;
    cout << "Podaj nazwe pliku z haslem: ";
    getline( cin, filename_pass ); // otwieranie pliku z haslem
    fin.open( filename_pass );
   
    if( !fin.is_open() ) // gdy nie ma takiego pliku
    {
        cout << "Otwarcie pliku nie powiodlo sie. Powrot do menu glownego." << endl << endl;
        show_menu();
    }
    else if( is_empt( fin ) ) // gdy plik jest pusty
    {
        cout << endl << "Plik jest pusty. Powrot do menu glownego." << endl << endl;
        show_menu();
    }
   
    ofstream outFile; // jesli poprzednie pliki udalo sie otworzyc, tworzony zostaje plik wynikowy
    outFile.open( "encrypted.txt" );
   
    string whole_text { };
    char c;
    inFile.get( c );
    do { // petla wczytujaca caly tekst do obiektu string
        whole_text += c;
        inFile.get( c );
    } while( !inFile.eof() );
   
    whole_text.erase( std::remove_if( whole_text.begin(), whole_text.end(), isspace ), whole_text.end() ); // usuwanie bialych znakow
   
    string whole_pass { };
    fin.get( c );
    do { // petla wczytujaca haslo do obiektu string
        whole_pass += c;
        fin.get( c );
    } while( !fin.eof() );
   
    whole_pass.erase( std::remove_if( whole_pass.begin(), whole_pass.end(), isspace ), whole_pass.end() ); // usuwanie bialych znakow
   
    unsigned int j = 0, i = 0;
    char single_sign, single_pass_sign;
   
    while( j != whole_text.size() ) // szyfrowanie
    {
        single_sign = whole_text[ j ];
       
        if( islower( single_sign ) ) // zamiana malego znaku na duzy
             single_sign = toupper( single_sign );
       
        if( i == whole_pass.size() ) // jesli haslo jest krotsze od tekstu szyfrowanego, powrot do pierwszego znaku
             i = 0;
       
        single_pass_sign = whole_pass[ i ];
       
        if( islower( single_pass_sign ) ) // zamiana malego znaku na duzy
             single_pass_sign = toupper( single_pass_sign );
       
        single_sign =( single_sign + single_pass_sign ) % 26 + 'A'; // zamiana, kwintesencja szyfrowania
        outFile << single_sign; // zapis do pliku wyjsciowego
        ++j;
        ++i;
    }
   
    cout << endl << "Tekst zostal pomyslnie zaszyfrowany!\nWynik szyfrowania znajduje sie w pliku encrypted.txt" << endl << endl;
   
    outFile.close();
   
    show_menu();
}

void decipherment()
{
    using std::cout;
    using std::string;
    using std::ifstream;
    using std::cin;
    using std::endl;
    using std::getline;
    using std::ofstream;
   
    string filename_toDeCipher;
    ifstream inFile;
    cout << "Podaj nazwe pliku z tekstem zaszyfrowanym: ";
    cin.clear();
    cin.ignore( std::numeric_limits < std::streamsize >::max(), '\n' );
    getline( cin, filename_toDeCipher ); // otwieranie pliku z tekstem zaszyfrowanym
    inFile.open( filename_toDeCipher );
   
    if( !inFile.is_open() ) // gdy nie ma takiego pliku
    {
        cout << endl << "Otwarcie pliku nie powiodlo sie. Powrot do menu glownego." << endl << endl;
        show_menu();
    }
    else if( is_empt( inFile ) ) // gdy plik jest pusty
    {
        cout << endl << "Plik jest pusty. Powrot do menu glownego." << endl << endl;
        show_menu();
    }
   
    string filename_pass;
    ifstream fin;
    cout << "Podaj nazwe pliku z haslem: ";
    getline( cin, filename_pass ); // otwieranie pliku z haslem
    fin.open( filename_pass );
   
    if( !fin.is_open() ) // gdy nie ma takiego pliku
    {
        cout << "Otwarcie pliku nie powiodlo sie. Powrot do menu glownego." << endl << endl;;
        show_menu();
    }
   
    ofstream outFile; // jesli poprzednie pliki udalo sie otworzyc, tworzony zostaje plik wynikowy
    outFile.open( "decrypted.txt" );
   
    string whole_text { };
    char c;
    inFile.get( c );
    do { // petla wczytujaca caly tekst do obiektu string
        whole_text += c;
        inFile.get( c );
    } while( !inFile.eof() );
   
    whole_text.erase( std::remove_if( whole_text.begin(), whole_text.end(), isspace ), whole_text.end() ); // usuwanie bialych znakow
   
    string whole_pass { };
    fin.get( c );
    do { // petla wczytujaca haslo do obiektu string
        whole_pass += c;
        fin.get( c );
    } while( !fin.eof() );
   
    whole_pass.erase( std::remove_if( whole_pass.begin(), whole_pass.end(), isspace ), whole_pass.end() ); // usuwanie bialych znakow
   
    char single_sign, single_pass_sign;
    int j = 0, i = 0;
   
    while( j != whole_text.size() ) // deszyfrowanie
    {
        single_sign = whole_text[ j ];
       
        if( islower( single_sign ) ) // zamiana malego znaku na duzy
             single_sign = toupper( single_sign );
       
        if( i == whole_pass.size() ) // jesli haslo jest krotsze od tekstu deszyfrowanego powrot do pierwszego znaku hasla
             i = 0;
       
        single_pass_sign = whole_pass[ i ];
       
        if( islower( single_pass_sign ) ) // zamiana malego znaku na duzy
             single_pass_sign = toupper( single_pass_sign );
       
        single_sign -= 65;
        single_pass_sign =( 26 - single_pass_sign ) % 26 + 65; // odwracanie hasla
       
        single_sign =( single_sign + single_pass_sign ) % 26 + 'A'; // szyfrowanie odwroconym haslem w celu odszyfrowania
        outFile << single_sign; // zapis do pliku wyjsciowego
        ++j;
        ++i;
    }
   
    cout << endl << "Tekst zostal pomyslnie rozszyfrowany!\nWynik rozszyfrowania znajduje sie w pliku decrypted.txt" << endl << endl;
   
    outFile.close();
   
    show_menu();
}

void show_menu()
{
    std::cout << "[1] Szyfrowanie" << std::endl;
    std::cout << "[2] Deszyfrowanie" << std::endl;
    std::cout << "[3] Wyjscie z programu" << std::endl;
    std::cout << "Wybor: _\b";
   
    int * wybor = new int;
   
    int i = 0;
    while( i < 1 ) // sprawdzanie poprawnosci wyboru opcji
    {
        std::cin.clear();
        std::cin.sync();
        std::cin >> * wybor;
        if( std::cin.fail() )
        {
            std::cout << "Wybrano zly rodzaj znaku wyboru. Prosze wpisac liczbe w przedziale 1-3 w celu wybrania odpowiedniej opcji."
            << std::endl << std::endl;
            show_menu();
            continue;
        }
        else
        {
            ++i;
        }
    }
   
    switch( * wybor ) {
    case 1: {
            std::cout << std::endl << "Wybrano funkcje szyfrujaca." << std::endl;
            encryption();
            break;
        }
    case 2: {
            std::cout << std::endl << "Wybrano funkcje deszyfrujaca." << std::endl;
            decipherment();
            break;
        }
    case 3: {
            std::exit( EXIT_SUCCESS );
            break;
        }
        default: {
            std::cout << std::endl << "Dokonano blednego wyboru. Prosze wybrac odpowiednia opcje." << std::endl;
            show_menu();
        }
    }
    delete wybor;
}

int main()
{
    using namespace std;
    cout << "Witaj w programie obslugujacym szyfr Vigenere\'a." << endl;
    show_menu();
   
    return EXIT_SUCCESS;
}
P-110756
« 1 »
  Strona 1 z 1