skm
skm

Reputation: 5649

Reading the information in string format from a file

I am trying to read the logic gates names and their inputs from a file. I have been given a .bench file which gives the information about the gate name and its inputs. I have written a code below which gives me perfect results if the information is given in the following format:

firstGate = NAND(inpA, inpB, inpC)
secGate = NAND(1, 2)
30 = NAND(A, B)

PROBLEM: But if there is a change in the "white space" before = sign , after , or at some other place then my code doesn't work. For example, if the file is given in the following format then i am not able to read it correctly

first=NAND(inpA, inpB, inpC) //no space before and after "="
sec = NAND(1,2) //no space after ","

My code which is working for the first case is below:

int main(int argc, char* argv[])
{
    //Reading the .bench file
    ifstream input_file;
    input_file.open("circuit.bench");
    if(input_file.fail())
    {
        cout << "Failed to open Bench file.\n";
        return 1;
    }
    ///////

    string line;        
    while (getline( input_file, line ))  
    {
        ///For NAND
        size_t  first_index_nand, second_index_nand;
        string gate_name;

        const string nand_str = "NAND(";
        if ((first_index_nand = line.find(nand_str)) != string::npos)
        {
            gate_name = line.substr(0, first_index_nand - 3);
            cout<<"\nGate name: "<<gate_name;

            first_index_nand += nand_str.length() - 1;
            cout<<"\nInput to this gate: ";
            for (; first_index_nand != string::npos; first_index_nand = second_index_nand)
            {
                if ((second_index_nand = line.find_first_of(",)", first_index_nand)) != string::npos)
                {
                    string input_name = line.substr(first_index_nand + 1, second_index_nand++ - first_index_nand - 1);  
                    cout<<" "<<input_name;
                }
            }
        }
        cout<<"\n";
    }

    return 0;

}

Query: How should i modify my code in such a way that it should be able to read the name of gate and its inputs irrespective of their position w.r.t whitespaces?

Note: I have to deal with this problem using C++ code and its libraries only.

Upvotes: 0

Views: 533

Answers (2)

abbadon
abbadon

Reputation: 48

You should do as @Rook and @Klaus suggested , maybe using a simple xml file without a dtd and a libraty like Xerces http://xerces.apache.org/xerces-c/.

If you want to use your file format you should remove all the white spaces by hand you can find how for example here: What's the best way to trim std::string? or here: remove whitespace in std::string. Only after that you can extract the data with your algorithm.

Anyway try this it should work.

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

using namespace std;

string trimWhiteSpaces(const string& line)
{
    string l = line;

    l.erase(std::remove_if( l.begin(), l.end(), ::isspace ), l.end());

    return l;
}

int main(int argc, char* argv[])
{
    cout << "starting... \n";

    ifstream _ifile;
    string fname = "gates.bench";

    _ifile.open(fname.c_str());
    if(!_ifile.is_open())
    {
        cerr << "Failed to open Bench file" << endl;
        exit(1);
    }

    string line;

    while(getline(_ifile, line))
    {

        line =  trimWhiteSpaces(line);

        size_t  first_index_nand, second_index_nand;
                string gate_name;

                const string nand_str = "NAND(";
                if ((first_index_nand = line.find(nand_str)) != string::npos)
                {
                    gate_name = line.substr(0, first_index_nand - 3);
                    cout<<"\nGate name: "<<gate_name;

                    first_index_nand += nand_str.length() - 1;
                    cout<<"\nInput to this gate: ";
                    for (; first_index_nand != string::npos; first_index_nand = second_index_nand)
                    {
                        if ((second_index_nand = line.find_first_of(",)", first_index_nand)) != string::npos)
                        {
                            string input_name = line.substr(first_index_nand + 1, second_index_nand++ - first_index_nand - 1);
                            cout<<" "<<input_name;
                        }
                    }
                }
                cout<<"\n";

    }

}

With a more OO approch

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

using namespace std;

class FileParser
{
public:
    FileParser (const string fname)
    {
        ifile.open(fname.c_str());
        if(!ifile.is_open())
        {
            exit(1);
        }
    }
    ~FileParser()
    {
        ifile.close();
    }
    void Parse()
    {
        string line;

        while(getline(ifile, line)){


        line =  trimWhiteSpaces(line);

        size_t  first_index_nand, second_index_nand;
        string gate_name;

        const string nand_str = "NAND(";
        if ((first_index_nand = line.find(nand_str)) != string::npos)
        {
        gate_name = line.substr(0, first_index_nand - 3);
        cout<<"\nGate name: "<<gate_name;

        first_index_nand += nand_str.length() - 1;
        cout<<"\nInput to this gate: ";
        for (; first_index_nand != string::npos; first_index_nand = second_index_nand)
        {
            if ((second_index_nand = line.find_first_of(",)", first_index_nand)) != string::npos)
            {

                string input_name = line.substr(first_index_nand + 1, second_index_nand++ - first_index_nand - 1);
                            cout<<" "<<input_name;
            }
           }
         }
         cout<<"\n";
    }
}
private:
    string trimWhiteSpaces(const string& line)
    {
        string l = line;

        l.erase(std::remove_if( l.begin(), l.end(), ::isspace ), l.end());

        return l;
    }

    ifstream ifile;

};

int main(int argc, char* argv[])
{

    FileParser fP("gates.bench");

    fP.Parse();
}

Upvotes: 0

Klaus
Klaus

Reputation: 25603

First answer: never write a handcrafted parser yourself :-)

1) use code generators for parsers like lex, yacc, bison ( a lot more ... )

2) you can get support for parsing from expect or regexp

3) look for serialization e.g. boost::serialize. If you modify the writer/reader it is possible to serialize into more complex formats which contains something like your configuration files.

If you really want to write your own parser, it mostly recommended to write a more or less complex state machine. But this can be done by tools much easier then by hand.

Sorr ythat I will not dig through your code, but my personal experience is, that it ends in tons of code lines to get a real working parser. And mostly the code is not maintainable anymore. So I want to advice you to use one of the three ( or any other option ) I provided :-)

Upvotes: 1

Related Questions