How to check if a line is all whitespaces in c++?

Viewed 53

My assignment is to read through a file that the user inputs and then check each line to see if there is a valid command on that line. For example, if the file contains this:

run        prog1
%
delete
% execute next command
delete myfile


copy file1 file2


print myfile

% terminate script

The expected output of my code is this:

Enter the name of a file to read from:

Total lines: 13
Commented lines: 3
Valid Command lines: 5
Invalid Command lines: 0
Run commands: 1
Print commands: 1
Copy commands: 1
Delete commands: 2

The code that I have is this:

#include <iostream>
#include <string>
#include <fstream>
using namespace std;

int main(){
    ifstream inClientFile;
    string filename;

    cout << "Enter the name of a file to read from:" << endl;
    cin >> filename;

    inClientFile.open(filename.c_str());
    if( !inClientFile)
    {
        cerr << endl;
        cerr << "File cannot be opened" << " " << filename << endl;
        exit (1);
    }

    string line;
    string commands;
    int total = 0, comment = 0, valid_lines = 0, invalid_lines = 0, run_lines = 0, print_lines = 0, copy_lines = 0, delete_lines = 0;

    while (getline(inClientFile,line)){
        total++;
        if(line.size()==0){
            continue;
        }
        else if(line[0]=='%'){
            comment++;
            continue;
        }
        else{
            int i=0;
            while (i<line.size() and line[i]!=' '){
                i++;
            }

            commands = line.substr(0,i);
            if(commands == "run"){
                run_lines++;
                valid_lines++;
            }
            else if(commands == "print"){
                print_lines++;
                valid_lines++;
            }
            else if(commands == "copy"){
                copy_lines++;
                valid_lines++;

            }
            else if(commands == "delete"){
                delete_lines++;
                valid_lines++;

            }
            else if(line.size()==0){
                continue;
            }
            else{
                cout<<"\nError: Unrecognizable command in line " <<total<<endl;
                invalid_lines++;
            }
        }
    }
    cout<<endl;
    cout << "Total lines: " << total << endl;
    cout << "Commented lines: " << comment << endl;
    cout << "Valid Command lines: " << valid_lines<< endl;
    cout << "Invalid Command lines: " << invalid_lines << endl;
    cout << "Run commands: " << run_lines << endl;
    cout << "Print commands: " << print_lines << endl;
    cout << "Copy commands: " << copy_lines << endl;
    cout << "Delete commands: " << delete_lines << endl;
    return 0;
}

The problem is that my code is reading lines that have all whitespaces as an invalid command. So the output ends up being:

Enter the name of a file to read from:                                                                                                                                                                                                   
                                                                                                                                                                                                                                         
Error: Unrecognizable command in line 7                                                                                                                                                                                                  
                                                                                                                                                                                                                                         
Error: Unrecognizable command in line 10                                                                                                                                                                                                 
                                                                                                                                                                                                                                         
Error: Unrecognizable command in line 12                                                                                                                                                                                                 
                                                                                                                                                                                                                                         
Total lines: 13                                                                                                                                                                                                                          
Commented lines: 3                                                                                                                                                                                                                       
Valid Command lines: 5                                                                                                                                                                                                                   
Invalid Command lines: 3                                                                                                                                                                                                                 
Run commands: 1                                                                                                                                                                                                                          
Print commands: 1                                                                                                                                                                                                                        
Copy commands: 1                                                                                                                                                                                                                         
Delete commands: 2

Please teach me how to read a line that has all whitespaces and then to ignore that line or just continue on. I thought the line:

if(line.size()==0){
            continue;
        }

would solve that issue but it doesn't work for two consecutive empty lines because the value of a line with all whitespaces is greater than the value of an empty line which is 0. Please help me!

1 Answers

Easiest thing to do is to use a std::istringstream and >> to pull apart the line. If the line is nothing but whitespace, >> will fail to find a token and the stream will be placed into a fail state. Test the stream state and you'll know if the line was empty of everything but whitepace.

Downside this will read

            run

as run and accept it as a valid token. If you will not accept a line that starts with whitespace

std::isspace(static_cast<unsigned char>(line[0]));

can be used to detect that case. See the notes in the std::isspace documentation for an explanation of the goofy looking cast.

I'd still use the istringstream to tokenize the line for simplicity. It will make fully tokenizing a command like

copy file1 file2

dead easy.

Updated code

#include <iostream>
#include <string>
#include <fstream>
#include <sstream> // for istringstream
using namespace std;

int main(){
    ifstream inClientFile;
    string filename;

    cout << "Enter the name of a file to read from:" << endl;
    cin >> filename;

    inClientFile.open(filename.c_str());
    if( !inClientFile)
    {
        cerr << endl;
        cerr << "File cannot be opened" << " " << filename << endl;
        exit (1);
    }

    string line;
    string commands;
    int total = 0, 
        comment = 0, 
        valid_lines = 0, 
        invalid_lines = 0, 
        run_lines = 0, 
        print_lines = 0, 
        copy_lines = 0, 
        delete_lines = 0;

    while (getline(inClientFile,line)){
        total++;
        if(line.size()==0){
            continue;
        }
        else if(line[0]=='%'){
            comment++;
            continue;
        }
        else{
            // test std::isspace(static_cast<unsigned char>(line[0])); here if
            // necessary
            std::istringstream strm(line); //use stream to split up the line 
            if (strm >>commands) // skip all whitespace leading to first 
                                 // whitepace-delimited token. If the line is 
                                 // nothing but whitespace, the read will fail.
                                 // downside: 
                                 //         run 
                                 // is now a valid command. May need extra checks
            {
                if(commands == "run"){
                    run_lines++;
                    valid_lines++;
                }
                else if(commands == "print"){
                    print_lines++;
                    valid_lines++;
                }
                else if(commands == "copy"){
                    copy_lines++;
                    valid_lines++;

                }
                else if(commands == "delete"){
                    delete_lines++;
                    valid_lines++;

                }
                else if(line.size()==0){
                    continue;
                }
                else{
                    cout<<"\nError: Unrecognizable command in line " <<total<<endl;
                    invalid_lines++;
                }
            }
            else // no token at all
            {
                continue; // bit of a waste now, but if someone adds more cases 
                          // after this one... One less possible bug.
            }
        }
    }
    cout<<endl;
    cout << "Total lines: " << total << endl;
    cout << "Commented lines: " << comment << endl;
    cout << "Valid Command lines: " << valid_lines<< endl;
    cout << "Invalid Command lines: " << invalid_lines << endl;
    cout << "Run commands: " << run_lines << endl;
    cout << "Print commands: " << print_lines << endl;
    cout << "Copy commands: " << copy_lines << endl;
    cout << "Delete commands: " << delete_lines << endl;
    return 0;
}
Related