326

如何确定一个字符串是否以 C++ 中的另一个字符串结尾?

4

22 回答 22

240

只需使用以下方式比较最后n 个字符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;
}
于 2009-05-17T08:34:04.790 回答
198

使用这个功能:

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());
}
于 2010-01-15T15:59:34.780 回答
168

使用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));
于 2011-06-12T21:36:04.233 回答
138

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.

于 2017-03-16T20:57:08.550 回答
44

我知道 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 );
}

于 2011-10-10T20:22:14.833 回答
26

当用于从两个字符串的末尾向后迭代时,该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() );
于 2009-05-18T08:12:09.333 回答
18

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

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

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

于 2013-09-08T06:59:46.337 回答
11

a成为一个字符串和b你要找的字符串。用于a.substr获取 的最后 n 个字符a并将它们与 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());
}
于 2009-05-17T08:27:09.533 回答
7

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

#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);
        }
    );
}
于 2018-01-03T22:27:31.287 回答
4

你可以使用string::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;
}
于 2009-05-17T08:38:51.813 回答
4

使用<algorithms>带有反向迭代的 std::equal 算法:

std::string LogExt = ".log";
if (std::equal(LogExt.rbegin(), LogExt.rend(), filename.rbegin())) {
   …
}
于 2020-05-07T14:46:55.577 回答
3

和上面一样,这是我的解决方案

 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());
  }
于 2016-03-01T22:46:54.483 回答
3

检查str是否有suffix,使用如下:

/*
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;
}
于 2016-12-02T08:41:29.370 回答
1

关于 Grzegorz Bazior 的反应。我使用了这个实现,但是原始的有错误(如果我将“..”与“.so”进行比较,则返回 true)。我建议修改功能:

bool endsWith(const string& s, const string& suffix)
{
    return s.size() >= suffix.size() && s.rfind(suffix) == (s.size()-suffix.size());
}
于 2014-12-05T08:47:54.300 回答
1

为类似的“startWith”问题找到了这个不错的答案:

如何检查 C++ std::string 是否以某个字符串开头,并将子字符串转换为 int?

您可以采用仅在字符串的最后一个位置进行搜索的解决方案:

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

通过这种方式,您可以使其简短、快速、使用标准 c++ 并使其具有可读性。

于 2020-06-09T10:19:01.417 回答
1
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 
于 2020-10-05T05:51:52.743 回答
1

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

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

可能效率不高,但易于实施。

于 2019-01-30T22:52:54.830 回答
1

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

std::filesystem::path("/foo/bar.txt").extension() == ".txt"
于 2021-03-25T17:01:56.250 回答
1

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

// 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;
}
于 2016-12-08T14:10:28.487 回答
0
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;
}
于 2020-09-10T08:02:11.357 回答
0

如果你和我一样,不喜欢 C++ 纯粹主义,这里有一个古老的 skool 混合体。当字符串包含多个字符时会有一些优势,因为大多数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;
}
于 2017-11-25T17:37:09.253 回答
0

我的两分钱:

bool endsWith(std::string str, std::string suffix)
{
   return str.find(suffix, str.size() - suffix.size()) != string::npos;
}
于 2020-06-16T18:42:58.553 回答