Nick Tsui
Nick Tsui

Reputation: 634

find exact string match in C++

Here is the code I used to detect the string in a line from a txt file:

int main()
{
    std::ifstream file( "C:\\log.txt" );

    std::string line;
    while(!file.eof())
    {
        while( std::getline( file, line ) )   
        {
            int found = -1;
            if((found = line.find("GetSA"))>-1)
                std::cout<<"We found GetSA."<<std::endl;
            else if ((found = line.find("GetVol"))>-1)
                std::cout<<"We found GetVol."<<std::endl;
            else if ((found = line.find("GetSphereSAandVol"))>-1)
                std::cout<<"We found GetSphereSAandVol."<<std::endl;
            else
                std::cout<<"We found nothing!"<<std::endl;

        }
    }
    std::cin.get();
}

And here is my log file:

GetSA (3.000000)

GetVol (3.000000)

GetSphereSAandVol (3.000000)

GetVol (3.000000)

GetSphereSAandVol (3.000000)

GetSA (3.00000)

The error is, the program will not go to find "GetSphereSAandVol", because it stops at "GetSA". Obviously, the program thinks "GetSphereSAandVol" contains "GetSA", so it will execute:

if(found = line.find("GetSA"))
    std::cout<<"We found GetSA."<<std::endl;

which is not exactly what I want, because I am expecting the program to execute:

else if (found = line.find("GetSphereSAandVol"))
    std::cout<<"We found GetSphereSAandVol."<<std::endl;

So, anyway I can avoid this? to get what I really want? Thanks a lot.

Upvotes: 4

Views: 15696

Answers (3)

Kerrek SB
Kerrek SB

Reputation: 477040

You misunderstand how find works. Read the documentation.

The conditionals should go like this:

if ((found = line.find("xyz")) != line.npos) { /* found "xyz" */ }

I would write your entire program like this:

int main(int argc, char * argv[])
{
    if (argc != 2) { std::cout << "Bad invocation\n"; return 0; }

    std::ifstream infile(argv[1]);

    if (!infile) { std::cout << "Bad filename '" << argv[1] << "'\n"; return 0; }

    for (std::string line; std::getline(infile, line); )
    {
        int pos;

        if ((pos = line.find("abc")) != line.npos)
        {
            std::cout << "Found line 'abc'\n";
            continue;
        }

        if ((pos = line.find("xyz")) != line.npos)
        {
            std::cout << "Found line 'xyz'\n";
            continue;
        }

        // ...

        std::cout << "Line '" << line << "' did not match anything.\n";
    }
}

Upvotes: 5

paddy
paddy

Reputation: 63471

The string::find function returns string::npos if not found. Otherwise it returns an index. You are assuming it returns a boolean and are testing accordingly. That will not work, because string::npos evaluates to a boolean truth (non-zero). Also, if the substring is at index zero, that will not pass.

You must instead do this:

if( std::string::npos != (found = line.find("GetSA")) )
   // etc...

Personally, I don't like the style of setting a value and testing in this way, but that's up to you. I might do this instead with a simple helper function:

bool FindSubString( std::string& str, const char *substr, int& pos )
{
    pos = str.find(substr);
    return pos != std::string::npos;
}

Then:

if( FindSubString( line, "GetSA", found ) )
    // etc...

But in your case, you're not even using the found variable. So you can ignore what I've said about style and just do:

if( std::string::npos != line.find("GetSA") )
    // etc...

Upvotes: 1

john
john

Reputation: 87959

Two errors, one you asked about and one you didn't.

Your if statements are wrong. You misunderstand how string::find works. This is the correct way

        if ((found = line.find("GetSA")) != string::npos)
           ...
        else if ((found = line.find("GetVol")) != string::npos)
           ...
        etc.

If string::find does not find what it's looking for it returns a special value string::npos. This is what your if conditions should test for.

Second error, lose the while (!file.eof()) loop, it's completely unnecessary.

Upvotes: 4

Related Questions