Réponses:
Comparez simplement les n derniers caractères en utilisant 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;
}
Utilisez cette fonction:
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()
En mode débogage, il lance:_DEBUG_ERROR("string iterator not decrementable");
Utilisation boost::algorithm::ends_with
(voir par exemple 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));
Notez que partir de c ++ 20 std :: string fournira finalement begin_with et ends_with . Il semble qu'il y ait une chance qu'en c ++ 30 chaînes en c ++ puissent enfin devenir utilisables, si vous ne lisez pas ceci dans un avenir lointain, vous pouvez utiliser ces départs avec / fin avec:
#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);
}
et quelques surcharges auxiliaires supplémentaires:
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, les chaînes c ++ sont clairement dysfonctionnelles et n'ont pas été conçues pour être utilisées dans le code du monde réel. Mais il y a un espoir que cela s'améliorera au moins.
Je connais la question pour C ++, mais si quelqu'un a besoin d'une bonne fonction C à l'ancienne pour le faire:
/* 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 );
}
La std::mismatch
méthode peut servir cet objectif lorsqu'elle est utilisée pour effectuer une itération en arrière à partir de la fin des deux chaînes:
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
: vous devez vérifier à l'avance que le suffixe supposé n'est pas plus long que la chaîne dans laquelle vous le recherchez. Négliger de vérifier cela conduit à un comportement indéfini.
À mon avis, la solution C ++ est la plus simple:
bool endsWith(const string& s, const string& suffix)
{
return s.rfind(suffix) == std::abs(s.size()-suffix.size());
}
s
au lieu de simplement tester la fin de celle-ci!
std::string::size()
est une opération à temps constant; il n'a pas besoin strlen
.
Soit a
une chaîne et b
la chaîne que vous recherchez. Utilisez a.substr
pour obtenir les n derniers caractères de a
et les comparer à b (où n est la longueur de b
)
Ou utiliser std::equal
(inclure <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());
}
Permettez-moi d'étendre la solution de Joseph avec la version insensible à la casse ( démo en ligne )
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);
}
);
}
la même chose que ci-dessus, voici ma solution
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
utilise 'string :: compare'? Pourquoi ne pas std::equal(start.begin(), start.end(), str.begin())
?
une autre option consiste à utiliser l'expression régulière. Le code suivant rend la recherche insensible aux majuscules / minuscules:
bool endsWithIgnoreCase(const std::string& str, const std::string& suffix) {
return std::regex_search(str,
std::regex(std::string(suffix) + "$", std::regex_constants::icase));
}
probablement pas aussi efficace, mais facile à mettre en œuvre.
vous pouvez utiliser string :: rfind
L'exemple complet basé sur les commentaires:
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;
}
Vérifiez si str a un suffixe , en utilisant ci-dessous:
/*
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;
}
Utilisez l'algorithme std :: equal <algorithms>
avec une itération inverse:
std::string LogExt = ".log";
if (std::equal(LogExt.rbegin(), LogExt.rend(), filename.rbegin())) {
…
}
Concernant la réponse de Grzegorz Bazior. J'ai utilisé cette implémentation, mais celle d'origine a un bug (retourne vrai si je compare ".." avec ".so"). Je propose une fonction modifiée:
bool endsWith(const string& s, const string& suffix)
{
return s.size() >= suffix.size() && s.rfind(suffix) == (s.size()-suffix.size());
}
J'ai pensé qu'il était logique de publier une solution brute qui n'utilise aucune fonction de bibliothèque ...
// 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;
}
En ajoutant un simple, std::tolower
nous pouvons rendre ce cas insensible
// 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;
}
J'ai trouvé cette belle réponse au problème similaire "startWith":
Vous pouvez adopter la solution pour rechercher uniquement à la dernière place de la chaîne:
bool endsWith(const std::string& stack, const std::string& needle) {
return stack.find(needle, stack.size() - needle.size()) != std::string::npos;
}
De cette façon, vous pouvez le rendre court, rapide, utiliser le c ++ standard et le rendre lisible.
Si vous êtes comme moi et que vous n'aimez pas le purisme C ++, voici un vieil hybride de skool. Il y a un avantage lorsque les chaînes sont plus d'une poignée de caractères, car la plupart des memcmp
implémentations comparent les mots machine lorsque cela est possible.
Vous devez contrôler le jeu de caractères. Par exemple, si cette approche est utilisée avec le type utf-8 ou wchar, il y a un inconvénient car elle ne prend pas en charge le mappage de caractères - par exemple, lorsque deux ou plusieurs caractères sont logiquement identiques .
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;
}
Mes deux centimes:
bool endsWith(std::string str, std::string suffix)
{
return str.find(suffix, str.size() - suffix.size()) != string::npos;
}