Search code examples
c++boostends-with

"Ends_with" function while reading an input file is not working


I am trying to create a C++ code that using boost libraries reads an input file like the following,

    1             12       13        0        0      1      0      INLE
    .
    .
    .

In this case, I must do an action if the condition specified on the last column of the right is INLE. I have the following code,

#include <iostream>
#include <fstream>
#include <string>
#include <boost/algorithm/string/predicate.hpp>


int main(int argc, const char * argv[])
{
    std::string line;
    const std::string B_condition = "INLE";
    std::ifstream myfile ("ramp.bnd");
    if (myfile.is_open())
    {
        while ( getline (myfile,line) )
        {
            if (boost::algorithm::ends_with(line,B_condition)==true)
            {
                std::cout << "Its True! \n"; // just for testing
                //add complete code
            }
        }
        myfile.close();
    }

    else std::cout << "Unable to open file";

    return 0;
}

while compiling there are no issues, but when I run, it doesnt shows anything.

By the other side, if I modify my boolean condition to false, it will print "Its true!" the number of lines that my input file has.

What am I doing wrong? Thanks!!


Solution

  • I can only assume that:

    • your file contains whitespace at the end (use trim)
    • your file has windows line ends (CRLF) but you're reading it as UNIX text files, meaning that the lines will include a trailing `\r' (CR) (often shown as ^M in various text editors/pagers).

    So, either

    • fix the line endings
    • trim whitespace from the lines before comparing
    • or both

    Best: use a 'proper' parser to do the work.

    Update adding a quick & dirty approach using Boost Spirit: see it Live On Coliru

    int main()
    {
        std::ifstream myfile("ramp.bnd");
        myfile.unsetf(std::ios::skipws);
    
        boost::spirit::istream_iterator f(myfile), l;
    
        using namespace qi;
        bool ok = phrase_parse(f, l,
                (repeat(7) [ int_ ] >> as_string[lexeme[+(char_ - eol)]])
                    [ phx::bind(process_line, _1, _2) ]
                % eol, // supports CRLF and LF
                blank);
    
        if (!ok)
            std::cerr << "Parse errors\n";
        if (f!=l)
            std::cerr << "Remaing input: '" << std::string(f,l) << "'\n";
    }
    

    As you can see, it validates the whole line, assuming (for now) that the columns are 7 integer values and a string (e.g. "INLE"). Now, the actual work is much simpler and can be implemented in a separate function:

    void process_line(std::vector<int> const& values, std::string const& kind)
    {
        if (kind == "INLE")
        {
            std::cout << "Column 1: " << values[0] << "\n";
        }
    }
    

    The actual processing function doesn't have to meddle with trimming, line ends, even parsing the details columns :)

    Full Code for reference

    #include <iostream>
    #include <fstream>
    #include <boost/spirit/include/qi.hpp>
    #include <boost/spirit/include/phoenix.hpp>
    
    namespace qi  = boost::spirit::qi;
    namespace phx = boost::phoenix;
    
    static const std::string B_condition = "INLE";
    
    void process_line(std::vector<int> const& values, std::string const& kind)
    {
        if (kind == "INLE")
        {
            std::cout << "Column 1: " << values[0] << "\n";
        }
    }
    
    int main()
    {
        std::ifstream myfile("ramp.bnd");
        myfile.unsetf(std::ios::skipws);
    
        boost::spirit::istream_iterator f(myfile), l;
    
        using namespace qi;
        bool ok = phrase_parse(f, l,
                (repeat(7) [ int_ ] >> as_string[lexeme[+(char_ - eol)]])
                    [ phx::bind(process_line, _1, _2) ]
                % eol, // supports CRLF and LF
                blank);
    
        if (!ok)
            std::cerr << "Parse errors\n";
        if (f!=l)
            std::cerr << "Remaing input: '" << std::string(f,l) << "'\n";
    }