tags:

views:

4127

answers:

6

How to find if string endswith another string c++

+2  A: 

Let a be a string and b the string you look for. Use a.substr to get the last n characters of a and compare them to b (where n is the length of b)

Or use std::equal (include <algorithm>)

Ex:

bool EndsWith(const string& a, const string& b) {
    if (b.size() > a.size()) return false;
    return std::equal(a.begin() + a.size() - b.size(), a.end(), b.begin());
}
Dario
How can i return true also if it ends after my string with \r or \n or both???thanks!
sofr
@Dario: Your solution using std::equal() is good, the one using substr() not so much -- unless you're using COW strings (and few people are I believe), substr() implies creating a second copy of part of the string, implying dynamic memory allocation is involved. This can may fail, and in any case means more memory is used than other solutions (and it's almost certainly slower than other solutions).
j_random_hacker
+16  A: 

Simply compare the last n characters using std::string::compare:

#include <iostream>

bool hasEnding (std::string const &fullString, std::string const &ending)
{
    if (fullString.length() > ending.length()) {
     return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending));
    } else {
     return false;
    }
}

int main ()
{
    std::string test1 = "binary";
    std::string test2 = "unary";
    std::string test3 = "tertiary";
    std::string test4 = "ry";
    std::string ending = "nary";

    std::cout << hasEnding (test1, ending) << std::endl;
    std::cout << hasEnding (test2, ending) << std::endl;
    std::cout << hasEnding (test3, ending) << std::endl;
    std::cout << hasEnding (test4, ending) << std::endl;

    return 0;
}
kdt
Yeah, this is the best way to do it, without doubt.
Noldorin
Very nice! I love these kinds of methods...
milan1612
I tried but somehow it didn't work I need my code also to handle if after the ending it has \r or \n etc.thanks for the help
sofr
I always hate calculating indices of substrings, it's very off-by-one prone... I'ld rather iterate backwards from the end of both strings, trying to find a mismatch.
xtofl
@sofr: Sounds like you should be stripping \r and \n from the end of your strings first (either just fullString or both it and ending). The following function does this in-place: void trimCrLf(string if (n if (n s.erase(n); }
j_random_hacker
I believe the comparison operator ought to be >= rather than simply >.
Skinniest Man
A: 

you can use string::rfind

The full Example based on comments:

bool EndsWith(string &str, string& key)
{
size_t keylen = key.length();
size_t strlen = str.length();

if(keylen =< strlen)
    return string::npos != str.rfind(key,strlen - keylen, keylen);
else return false;
}
Ahmed Said
-1. Yes you could use it, but it's unnecessarily slow in the event that the string does not end with the supplied ending -- scanning will continue all the way back to the start of the string. Also, you don't mention that you need a subsequent test to make sure that the ending matches **at the end of the string**, rather than elsewhere in the string.
j_random_hacker
I just put the link of the needed function and I think it is very easy to do it from the documentationstr.rfind(key,str.length()-key.length(),key.length());
Ahmed Said
OK, that's efficient -- but in that case string::find() would work just as well. Also you need to mention the case where key.length() > str.length() -- the code you suggest in your comment will crash in this case. If you update your answer with this info I'll drop my -1.
j_random_hacker
I modified the answer
Ahmed Said
+4  A: 

The std::mismatch method can serve this purpose when used to backwards iterate from the end of both strings:

const string sNoFruit = "ThisOneEndsOnNothingMuchFruitLike";
const string sOrange = "ThisOneEndsOnOrange";

const string sPattern = "Orange";

assert( mismatch( sPattern.rbegin(), sPattern.rend(), sNoFruit.rbegin() )
          .first != sPattern.rend() );

assert( mismatch( sPattern.rbegin(), sPattern.rend(), sOrange.rbegin() )
          .first == sPattern.rend() );
xtofl
+1. I'd never noticed std::mismatch() before -- I wonder what else is in that algorithms header file that I've never looked at...
j_random_hacker
I think that's worth a SO question on it's own: have you ever browsed through the stl functions available?
xtofl
A: 

If you want to ignore '\n' and '\r' at the end of the string, you could modify jcs' solution as follows:

#include <iostream>

bool hasEnding (std::string const &fullString, std::string const &ending)
{
    unsigned int lastMatchPos = fullString.rfind(ending); // Find the last occurrence of ending
    bool isEnding = lastMatchPos != std::string::npos; // Make sure it's found at least once

    // If the string was found, make sure that any characters that follow it are the ones we're trying to ignore
    for( int i = lastMatchPos + ending.length(); (i < fullString.length()) && isEnding; i++)
    {
        if( (fullString[i] != '\n') &&
            (fullString[i] != '\r') )
        {
            isEnding = false;
        }
    }

    return isEnding;
}

int _tmain(int argc, _TCHAR* argv[])
{
    std::string test1 = "binary";
    std::string test2 = "unary\n\r";
    std::string test3 = "tertiary";
    std::string test4 = "ry";
    std::string ending = "nary";

    std::cout << hasEnding (test1, ending) << std::endl;
    std::cout << hasEnding (test2, ending) << std::endl;
    std::cout << hasEnding (test3, ending) << std::endl;
    std::cout << hasEnding (test4, ending) << std::endl;

    getchar();

    return 0;
}
Jon Cage
rfind could spend a lot of time scanning the string looking for a match that isn't at the end, only to throw that work away later. kdt's answer is better and can be easily modified to start the comparison earlier in fullString--just subtract the number of skippable characters appearing at the end of fullString.
Ken Fox
+1  A: 

what about:

if (std::equal(suffix.rbegin(), suffix.rend(), str.rbegin())
{
    //ends with....
}
else
{
    //does not end with...
}
Joseph