Find out if string ends with another string in C++

C++StringEnds With

C++ Problem Overview


How can I find out if a string ends with another string in C++?

C++ Solutions


Solution 1 - C++

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;
}

Solution 2 - C++

Use this function:

inline bool ends_with(std::string const & value, std::string const & ending)
{
    if (ending.size() > value.size()) return false;
    return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
}

Solution 3 - C++

Use boost::algorithm::ends_with (see e.g. http://www.boost.org/doc/libs/1_34_0/doc/html/boost/algorithm/ends_with.html ):

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

// works with const char* 
assert(boost::algorithm::ends_with("mystring", "ing"));

// also works with std::string
std::string haystack("mystring");
std::string needle("ing");
assert(boost::algorithm::ends_with(haystack, needle));

std::string haystack2("ng");
assert(! boost::algorithm::ends_with(haystack2, needle));

Solution 4 - C++

Note, that starting from c++20 std::string will finally provide starts_with and ends_with. Seems like there is a chance that by c++30 strings in c++ might finally become usable, if you aren't reading this from distant future, you can use these startsWith/endsWith with C++17:

#if __cplusplus >= 201703L // C++17 and later 
#include <string_view>

static bool endsWith(std::string_view str, std::string_view suffix)
{
    return str.size() >= suffix.size() && 0 == str.compare(str.size()-suffix.size(), suffix.size(), suffix);
}

static bool startsWith(std::string_view str, std::string_view prefix)
{
    return str.size() >= prefix.size() && 0 == str.compare(0, prefix.size(), prefix);
}
#endif // C++17

If you are stuck with older C++, you may use these:

#if __cplusplus < 201703L // pre C++17
#include <string>

static bool endsWith(const std::string& str, const std::string& suffix)
{
    return str.size() >= suffix.size() && 0 == str.compare(str.size()-suffix.size(), suffix.size(), suffix);
}

static bool startsWith(const std::string& str, const std::string& prefix)
{
    return str.size() >= prefix.size() && 0 == str.compare(0, prefix.size(), prefix);
}

and some extra helper overloads:

static bool endsWith(const std::string& str, const char* suffix, unsigned suffixLen)
{
    return str.size() >= suffixLen && 0 == str.compare(str.size()-suffixLen, suffixLen, suffix, suffixLen);
}

static bool endsWith(const std::string& str, const char* suffix)
{
    return endsWith(str, suffix, std::string::traits_type::length(suffix));
}

static bool startsWith(const std::string& str, const char* prefix, unsigned prefixLen)
{
    return str.size() >= prefixLen && 0 == str.compare(0, prefixLen, prefix, prefixLen);
}

static bool startsWith(const std::string& str, const char* prefix)
{
    return startsWith(str, prefix, std::string::traits_type::length(prefix));
}
#endif

IMO, c++ strings are clearly dysfunctional, and weren't made to be used in real world code. But there is a hope that this will get better at least.

Solution 5 - C++

I know the question's for C++, but if anyone needs a good ol' fashioned C function to do this:


/*  returns 1 iff str ends with suffix  */
int str_ends_with(const char * str, const char * suffix) {




if( str == NULL || suffix == NULL )
return 0;




size_t str_len = strlen(str);
size_t suffix_len = strlen(suffix);




if(suffix_len > str_len)
return 0;




return 0 == strncmp( str + str_len - suffix_len, suffix, suffix_len );
}

return 0 == strncmp( str + str_len - suffix_len, suffix, suffix_len ); }

Solution 6 - C++

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() );

Solution 7 - C++

In my opinion simplest, C++ solution is:

bool endsWith(const std::string& s, const std::string& suffix)
{
	return s.rfind(suffix) == std::abs(s.size()-suffix.size());
}

Warning: If the match fails, this will search the entire string backwards before giving up, and thus potentially waste a lot of cycles.

Solution 8 - C++

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());
}

Solution 9 - C++

Let me extend Joseph's solution with the case insensitive version (online demo)

#include <string>
#include <cctype>

static bool EndsWithCaseInsensitive(const std::string& value, const std::string& ending) {
    if (ending.size() > value.size()) {
        return false;
    }
    return std::equal(ending.crbegin(), ending.crend(), value.crbegin(),
        [](const unsigned char a, const unsigned char b) {
            return std::tolower(a) == std::tolower(b);
        }
    );
}

Solution 10 - C++

Use std::equal algorithm from <algorithms> with reverse iteration:

std::string LogExt = ".log";
if (std::equal(LogExt.rbegin(), LogExt.rend(), filename.rbegin())) {
   …
}

Starting from C++20 ends_with introduced.

Solution 11 - C++

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;
}

Solution 12 - C++

the very same as above, here is my solution

 template<typename TString>
  inline bool starts_with(const TString& str, const TString& start) {
    if (start.size() > str.size()) return false;
    return str.compare(0, start.size(), start) == 0;
  }
  template<typename TString>
  inline bool ends_with(const TString& str, const TString& end) {
    if (end.size() > str.size()) return false;
    return std::equal(end.rbegin(), end.rend(), str.rbegin());
  }

Solution 13 - C++

Check if str has suffix, using below:

/*
Check string is end with extension/suffix
*/
int strEndWith(char* str, const char* suffix)
{
  size_t strLen = strlen(str);
  size_t suffixLen = strlen(suffix);
  if (suffixLen <= strLen) {
    return strncmp(str + strLen - suffixLen, suffix, suffixLen) == 0;
  }
  return 0;
}

Solution 14 - C++

Regarding Grzegorz Bazior response. I used this implementation, but original one has bug (returns true if I compare ".." with ".so"). I propose modified function:

bool endsWith(const string& s, const string& suffix)
{
    return s.size() >= suffix.size() && s.rfind(suffix) == (s.size()-suffix.size());
}

Solution 15 - C++

I thought it makes sense to post a raw solution that doesn't use any library functions...

// Checks whether `str' ends with `suffix'
bool endsWith(const std::string& str, const std::string& suffix) {
	if (&suffix == &str) return true; // str and suffix are the same string
	if (suffix.length() > str.length()) return false;
	size_t delta = str.length() - suffix.length();
	for (size_t i = 0; i < suffix.length(); ++i) {
		if (suffix[i] != str[delta + i]) return false;
	}
	return true;
}

Adding a simple std::tolower we can make this case insensitive

// Checks whether `str' ends with `suffix' ignoring case
bool endsWithIgnoreCase(const std::string& str, const std::string& suffix) {
	if (&suffix == &str) return true; // str and suffix are the same string
	if (suffix.length() > str.length()) return false;
	size_t delta = str.length() - suffix.length();
	for (size_t i = 0; i < suffix.length(); ++i) {
		if (std::tolower(suffix[i]) != std::tolower(str[delta + i])) return false;
	}
	return true;
}

Solution 16 - C++

another option is to use regex. The following code makes the search insensitive to upper/lower case:

bool endsWithIgnoreCase(const std::string& str, const std::string& suffix) {
  return std::regex_search(str,
     std::regex(std::string(suffix) + "$", std::regex_constants::icase));
}

probably not so efficient, but easy to implement.

Solution 17 - C++

Found this nice answer to the similar "startWith"-problem:

https://stackoverflow.com/questions/1878001/how-do-i-check-if-a-c-stdstring-starts-with-a-certain-string-and-convert-a

You can adopt the solution to only search at the last place in the string:

bool endsWith(const std::string& stack, const std::string& needle) {
    return stack.find(needle, stack.size() - needle.size()) != std::string::npos;
}

This way you can make it short, fast, use standard c++ and make it readable.

Solution 18 - C++

bool EndsWith(const std::string& data, const std::string& suffix)
{
	return data.find(suffix, data.size() - suffix.size()) != std::string::npos;
}

Tests

#include <iostream>
int main()
{
   cout << EndsWith(u8"o!hello!1", u8"o!") << endl; 
   cout << EndsWith(u8"o!hello!", u8"o!") << endl; 
   cout << EndsWith(u8"hello!", u8"o!") << endl; 
   cout << EndsWith(u8"o!hello!o!", u8"o!") << endl; 
   return 0;
}

Output

0 
1 
1 
1 

Solution 19 - C++

If, like me, you need endsWith to check a file extension, you can use the std::filesystem library:

std::filesystem::path("/foo/bar.txt").extension() == ".txt"

Solution 20 - C++

If you're like me and no so into C++ purism, here's an old skool hybrid. There's some advantage when strings are more than a handful of characters, as most memcmp implementations compare machine words when possible.

You need to be in control of the character set. For example, if this approach is used with utf-8 or wchar type, there's some disadvantage as it won't support character mapping - e.g., when two or more characters are logically identical.

bool starts_with(std::string const & value, std::string const & prefix)
{
    size_t valueSize = value.size();
    size_t prefixSize = prefix.size();

    if (prefixSize > valueSize)
    {
        return false;
    }

    return memcmp(value.data(), prefix.data(), prefixSize) == 0;
}


bool ends_with(std::string const & value, std::string const & suffix)
{
    size_t valueSize = value.size();
    size_t suffixSize = suffix.size();

    if (suffixSize > valueSize)
    {
        return false;
    }

    const char * valuePtr = value.data() + valueSize - suffixSize;

    return memcmp(valuePtr, suffix.data(), suffixSize) == 0;
}

Solution 21 - C++

My two cents:

bool endsWith(std::string str, std::string suffix)
{
   return str.find(suffix, str.size() - suffix.size()) != string::npos;
}

Solution 22 - C++

bool endswith(const std::string &str, const std::string &suffix)
{
    string::size_type totalSize = str.size();
    string::size_type suffixSize = suffix.size();

    if(totalSize < suffixSize) {
        return false;
    }

    return str.compare(totalSize - suffixSize, suffixSize, suffix) == 0;
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionsofrView Question on Stackoverflow
Solution 1 - C++kdtView Answer on Stackoverflow
Solution 2 - C++JosephView Answer on Stackoverflow
Solution 3 - C++Andre HolznerView Answer on Stackoverflow
Solution 4 - C++Pavel PView Answer on Stackoverflow
Solution 5 - C++TomView Answer on Stackoverflow
Solution 6 - C++xtoflView Answer on Stackoverflow
Solution 7 - C++baziorekView Answer on Stackoverflow
Solution 8 - C++DarioView Answer on Stackoverflow
Solution 9 - C++PolarBearView Answer on Stackoverflow
Solution 10 - C++Sergei KrivonosView Answer on Stackoverflow
Solution 11 - C++AhmedView Answer on Stackoverflow
Solution 12 - C++dodjangoView Answer on Stackoverflow
Solution 13 - C++James YangView Answer on Stackoverflow
Solution 14 - C++Andrew123View Answer on Stackoverflow
Solution 15 - C++cute_ptrView Answer on Stackoverflow
Solution 16 - C++Julien PiletView Answer on Stackoverflow
Solution 17 - C++LasersköldView Answer on Stackoverflow
Solution 18 - C++JomaView Answer on Stackoverflow
Solution 19 - C++DanView Answer on Stackoverflow
Solution 20 - C++jwsView Answer on Stackoverflow
Solution 21 - C++drop tableView Answer on Stackoverflow
Solution 22 - C++user3018158View Answer on Stackoverflow