Ответы:
Просто сравните последние 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;
}
Используйте эту функцию:
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());
}
std::equal(suffix.rbegin(), suffix.rend(), str.rbegin()
в режиме отладки он выдает:_DEBUG_ERROR("string iterator not decrementable");
Используйте 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 ++ 20 std :: string в конечном итоге предоставит start_with и end_with . Похоже, что есть шанс, что с ++ 30 строки в с ++ могут наконец стать пригодными для использования, если вы не читаете это из далекого будущего, вы можете использовать эти startWith / EndWith:
#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);
}
и некоторые дополнительные вспомогательные перегрузки:
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));
}
IMO, строки c ++ явно не функционируют и не предназначены для использования в реальном коде. Но есть надежда, что это станет лучше, по крайней мере.
Я знаю вопрос о 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 );
}
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() );
std::equal
: вам нужно заранее проверить, что предполагаемый суффикс не длиннее строки, в которой вы его ищете. Пренебрежение проверкой приводит к неопределенному поведению.
На мой взгляд, самое простое решение C ++ это:
bool endsWith(const string& s, const string& suffix)
{
return s.rfind(suffix) == std::abs(s.size()-suffix.size());
}
s
а не просто проверять ее конец!
std::string::size()
- операция с постоянным временем; это не нужно strlen
.
Позвольте 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());
}
Позвольте мне расширить решение Джозефа с учетом версии без учета регистра ( онлайн-демонстрация )
static bool EndsWithCaseInsensitive(const std::string& value, const std::string& ending) {
if (ending.size() > value.size()) {
return false;
}
return std::equal(ending.rbegin(), ending.rend(), value.rbegin(),
[](const char a, const char b) {
return tolower(a) == tolower(b);
}
);
}
то же самое, что и выше, вот мое решение
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());
}
starts_with
используется строка :: сравнить? Почему нет std::equal(start.begin(), start.end(), str.begin())
?
Другой вариант - использовать регулярные выражения. Следующий код делает поиск нечувствительным к верхнему / нижнему регистру:
bool endsWithIgnoreCase(const std::string& str, const std::string& suffix) {
return std::regex_search(str,
std::regex(std::string(suffix) + "$", std::regex_constants::icase));
}
Вероятно, не так эффективно, но легко реализовать.
ты можешь использовать 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;
}
Проверьте, есть ли суффикс 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;
}
Используйте алгоритм std :: equal <algorithms>
с обратной итерацией:
std::string LogExt = ".log";
if (std::equal(LogExt.rbegin(), LogExt.rend(), filename.rbegin())) {
…
}
Относительно ответа Гжегожа Базиора. Я использовал эту реализацию, но оригинальная имеет ошибку (возвращает true, если я сравниваю «..» с «.so»). Я предлагаю модифицированную функцию:
bool endsWith(const string& s, const string& suffix)
{
return s.size() >= suffix.size() && s.rfind(suffix) == (s.size()-suffix.size());
}
Я думал, что имеет смысл опубликовать сырое решение, которое не использует библиотечные функции ...
// 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;
}
Нашел этот хороший ответ на похожую проблему "startWith":
Вы можете принять решение, чтобы искать только в последнем месте в строке:
bool endsWith(const std::string& stack, const std::string& needle) {
return stack.find(needle, stack.size() - needle.size()) != std::string::npos;
}
Таким образом, вы можете сделать его коротким, быстрым, использовать стандартный 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;
}