Antworten:
Vergleichen Sie einfach die letzten n Zeichen mit 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;
}
Verwenden Sie diese Funktion:
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()
Im Debug-Modus wird _DEBUG_ERROR("string iterator not decrementable");
Verwendung boost::algorithm::ends_with
(siehe z. B. 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));
Beachten Sie, dass ab c ++ 20 std :: string endlich Start_with und Endes_with liefert . Es scheint, dass es eine Chance gibt, dass durch c ++ 30 Zeichenfolgen in c ++ endlich verwendbar werden. Wenn Sie dies nicht aus ferner Zukunft lesen, können Sie diese StartsWith / EndsWith verwenden:
#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);
}
und einige zusätzliche Helferüberladungen:
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 ++ - Zeichenfolgen sind eindeutig nicht funktionsfähig und wurden nicht für die Verwendung im Code der realen Welt entwickelt. Aber es besteht die Hoffnung, dass dies zumindest besser wird.
Ich kenne die Frage für C ++, aber wenn jemand eine gute, altmodische C-Funktion benötigt, um dies zu tun:
/* 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 );
}
Die std::mismatch
Methode kann diesen Zweck erfüllen, wenn sie verwendet wird, um vom Ende beider Zeichenfolgen rückwärts zu iterieren:
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
: Sie müssen im Voraus überprüfen, ob das angebliche Suffix nicht länger als die Zeichenfolge ist, in der Sie danach suchen. Wenn Sie dies nicht überprüfen, führt dies zu undefiniertem Verhalten.
Meiner Meinung nach ist die einfachste C ++ - Lösung:
bool endsWith(const string& s, const string& suffix)
{
return s.rfind(suffix) == std::abs(s.size()-suffix.size());
}
s
anstatt nur das Ende zu testen!
std::string::size()
ist eine Operation mit konstanter Zeit. es braucht nicht strlen
.
Sei a
eine Zeichenfolge und b
die Zeichenfolge, nach der du suchst. Verwenden Sie a.substr
diese Option , um die letzten n Zeichen von a
abzurufen und mit b zu vergleichen (wobei n die Länge von istb
).
Oder verwenden Sie std::equal
(enthalten<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());
}
Lassen Sie mich Josephs Lösung mit der Version ohne Berücksichtigung der Groß- und Kleinschreibung erweitern ( Online-Demo )
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);
}
);
}
Genau wie oben, hier ist meine Lösung
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
wird 'string :: compare' verwendet? Warum nicht std::equal(start.begin(), start.end(), str.begin())
?
Eine andere Möglichkeit ist die Verwendung von Regex. Der folgende Code macht die Suche unempfindlich gegenüber Groß- / Kleinschreibung:
bool endsWithIgnoreCase(const std::string& str, const std::string& suffix) {
return std::regex_search(str,
std::regex(std::string(suffix) + "$", std::regex_constants::icase));
}
wahrscheinlich nicht so effizient, aber einfach zu implementieren.
Sie können string :: rfind verwenden
Das vollständige Beispiel basiert auf Kommentaren:
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;
}
Überprüfen Sie, ob str das Suffix hat , indem Sie Folgendes verwenden:
/*
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;
}
Verwenden Sie den Algorithmus std :: same <algorithms>
mit umgekehrter Iteration:
std::string LogExt = ".log";
if (std::equal(LogExt.rbegin(), LogExt.rend(), filename.rbegin())) {
…
}
In Bezug auf Grzegorz Bazior Antwort. Ich habe diese Implementierung verwendet, aber die ursprüngliche hat einen Fehler (gibt true zurück, wenn ich ".." mit ".so" vergleiche). Ich schlage eine modifizierte Funktion vor:
bool endsWith(const string& s, const string& suffix)
{
return s.size() >= suffix.size() && s.rfind(suffix) == (s.size()-suffix.size());
}
Ich fand es sinnvoll, eine Rohlösung zu veröffentlichen, die keine Bibliotheksfunktionen verwendet ...
// 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;
}
Wenn std::tolower
wir eine einfache hinzufügen, können wir diesen Fall unempfindlich machen
// 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;
}
Fand diese nette Antwort auf das ähnliche "startWith" -Problem:
Sie können die Lösung verwenden, um nur an der letzten Stelle in der Zeichenfolge zu suchen:
bool endsWith(const std::string& stack, const std::string& needle) {
return stack.find(needle, stack.size() - needle.size()) != std::string::npos;
}
Auf diese Weise können Sie es kurz und schnell machen, Standard-C ++ verwenden und es lesbar machen.
Wenn Sie wie ich sind und sich nicht für C ++ - Purismus interessieren, dann ist hier ein alter Skool-Hybrid. Es gibt einige Vorteile, wenn Zeichenfolgen mehr als eine Handvoll Zeichen enthalten, da die meisten memcmp
Implementierungen Maschinenwörter vergleichen, wenn dies möglich ist.
Sie müssen die Kontrolle über den Zeichensatz haben. Wenn dieser Ansatz beispielsweise mit utf-8 oder wchar verwendet wird, gibt es einige Nachteile, da er die Zeichenzuordnung nicht unterstützt - z. B. wenn zwei oder mehr Zeichen logisch identisch sind .
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;
}
Meine zwei Cent:
bool endsWith(std::string str, std::string suffix)
{
return str.find(suffix, str.size() - suffix.size()) != string::npos;
}