在c++中找出字符串是否以另一个字符串结尾

在c++中,如何知道字符串是否以另一个字符串结束?

251592 次浏览

a为字符串,b为你要找的字符串。使用a.substr获取a的最后n个字符,并将它们与b进行比较(其中n是b的长度)

或者使用std::equal(包括<algorithm>)

例:

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

简单地用std::string::compare比较最后的n字符:

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

你可以使用字符串:rfind

基于注释的完整示例:

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

std::mismatch方法可以用于从两个字符串的末尾开始向后迭代:

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

使用这个函数:

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

使用boost::algorithm::ends_with(参见例如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));

我知道这个问题是针对c++的,但如果有人需要一个很好的老式C函数来做到这一点:


/*  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 );
}

在我看来,最简单的c++解决方案是:

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

警告:如果匹配失败,这将在放弃之前向后搜索整个字符串,因此可能会浪费很多循环。

关于Grzegorz Bazior反应。我使用了这个实现,但原来的一个有bug(如果我比较“..”与“.so”,则返回true)。 我建议修改函数:

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

和上面一样,这是我的解

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

检查str是否有后缀,使用下面的方法:

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

我认为发布一个不使用任何库函数的原始解决方案是有意义的…

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

添加一个简单的std::tolower可以使这个大小写不敏感

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

注意,从c + + 20开始,std::string将最终提供starts_withends_with。似乎有机会在c++中使用c++30字符串,如果你不是在遥远的将来阅读这篇文章,你可以在c++ 17中使用这些startsWith/endsWith:

#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

如果你坚持使用旧的c++,你可以使用这些:

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

并且一些额外的helper会重载:

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

在我看来,c++字符串显然是功能失调的,而且不适合在现实世界的代码中使用。但至少有希望情况会有所好转。

如果你像我一样,对c++的纯粹主义不那么感兴趣,这里有一个古老的混合体。当字符串多于几个字符时,会有一些优势,因为大多数memcmp实现都尽可能比较机器单词。

你需要控制字符集。例如,如果这种方法与utf-8或wchar类型一起使用,则会有一些缺点,因为它不支持字符映射——例如,当两个或多个字符为逻辑上相同的时。

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

让我用不区分大小写的版本(在线演示)扩展约瑟的解决方案

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

另一种选择是使用正则表达式。下面的代码使搜索对大小写不敏感:

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

可能不是很有效,但是很容易实现。

使用std::equal算法从<algorithms>反向迭代:

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

从c++ 20开始介绍ends_with

我的观点是:

bool endsWith(std::string str, std::string suffix)
{
return str.find(suffix, str.size() - suffix.size()) != string::npos;
}
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;
}
bool EndsWith(const std::string& data, const std::string& suffix)
{
return data.find(suffix, data.size() - suffix.size()) != std::string::npos;
}


测试

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

输出

0
1
1
1

如果像我一样,你需要endsWith来检查文件扩展名,你可以使用std::filesystem库:

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