Risposte:
Confronta semplicemente gli ultimi n caratteri usando 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;
}
Usa questa funzione:
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()
in modalità debug, genera:_DEBUG_ERROR("string iterator not decrementable");
Usa boost::algorithm::ends_with
(vedi ad esempio 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));
Nota che a partire da c ++ 20 std :: string fornirà infine start_with e End_with . Sembra che ci sia la possibilità che da c ++ 30 stringhe in c ++ possano finalmente diventare utilizzabili, se non stai leggendo questo da un futuro lontano, puoi usare questi inizi Con / Fine Con
#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);
}
e alcuni sovraccarichi di aiuto aggiuntivi:
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));
}
Le stringhe IMO, c ++ sono chiaramente disfunzionali e non sono state progettate per essere utilizzate nel codice del mondo reale. Ma c'è una speranza che questo possa migliorare almeno.
Conosco la domanda per C ++, ma se qualcuno ha bisogno di una buona funzione C vecchio stile per fare questo:
/* 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 );
}
Il std::mismatch
metodo può servire a questo scopo quando usato per iterare all'indietro dalla fine di entrambe le stringhe:
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
: è necessario verificare in anticipo che il supposto suffisso non sia più lungo della stringa in cui lo si sta cercando. Trascurare di verificare ciò porta a un comportamento indefinito.
A mio avviso, la soluzione C ++ più semplice è:
bool endsWith(const string& s, const string& suffix)
{
return s.rfind(suffix) == std::abs(s.size()-suffix.size());
}
s
invece di testarne la fine!
std::string::size()
è un'operazione a tempo costante; non serve strlen
.
Lascia che a
sia una stringa e b
la stringa che cerchi. Utilizzare a.substr
per ottenere gli ultimi n caratteri di a
e confrontarli con b (dove n è la lunghezza di b
)
Oppure usa std::equal
(includi <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());
}
Vorrei estendere la soluzione di Joseph con la versione senza distinzione tra maiuscole e minuscole ( demo online )
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);
}
);
}
esattamente come sopra, ecco la mia soluzione
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
usa 'string :: compare'? Perché no std::equal(start.begin(), start.end(), str.begin())
?
un'altra opzione è usare regex. Il codice seguente rende la ricerca insensibile alle maiuscole / minuscole:
bool endsWithIgnoreCase(const std::string& str, const std::string& suffix) {
return std::regex_search(str,
std::regex(std::string(suffix) + "$", std::regex_constants::icase));
}
probabilmente non così efficiente, ma facile da implementare.
puoi usare string :: rfind
L'esempio completo basato sui commenti:
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;
}
Controlla se str ha il suffisso , usando di seguito:
/*
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;
}
Usa l'algoritmo std :: equal <algorithms>
con iterazione inversa:
std::string LogExt = ".log";
if (std::equal(LogExt.rbegin(), LogExt.rend(), filename.rbegin())) {
…
}
Per quanto riguarda la risposta di Grzegorz Bazior. Ho usato questa implementazione, ma quella originale ha un bug (restituisce vero se confronto ".." con ".so"). Propongo funzione modificata:
bool endsWith(const string& s, const string& suffix)
{
return s.size() >= suffix.size() && s.rfind(suffix) == (s.size()-suffix.size());
}
Ho pensato che fosse logico pubblicare una soluzione grezza che non utilizza alcuna funzione di libreria ...
// 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;
}
Aggiungendo un semplice std::tolower
possiamo rendere insensibile questo caso
// 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;
}
Ho trovato questa bella risposta al simile problema "startWith":
Puoi adottare la soluzione per cercare solo l'ultimo posto nella stringa:
bool endsWith(const std::string& stack, const std::string& needle) {
return stack.find(needle, stack.size() - needle.size()) != std::string::npos;
}
In questo modo puoi renderlo breve, veloce, usare lo standard c ++ e renderlo leggibile.
Se sei come me e non così nel purismo C ++, ecco un vecchio ibrido skool. C'è qualche vantaggio quando le stringhe sono più di una manciata di caratteri, poiché la maggior parte delle memcmp
implementazioni confronta le parole automatiche quando possibile.
Devi avere il controllo del set di caratteri. Ad esempio, se questo approccio viene utilizzato con il tipo utf-8 o wchar, c'è qualche svantaggio in quanto non supporta la mappatura dei caratteri, ad esempio quando due o più caratteri sono logicamente identici .
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;
}
I miei due centesimi:
bool endsWith(std::string str, std::string suffix)
{
return str.find(suffix, str.size() - suffix.size()) != string::npos;
}