web-dev-qa-db-fra.com

Rechercher si la chaîne se termine par une autre chaîne en C++

Comment puis-je savoir si une chaîne se termine par une autre chaîne en C++?

229
sofr

Comparez simplement les derniers caractères n à l’aide de 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;
}
185
kdt

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());
}
154
Joseph

Utilisez 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));
143
Andre Holzner

Je sais que la question s'adresse au C++, mais si quelqu'un a besoin d'une bonne fonction C 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 );
}
38
Tom

Notez que, à partir de c ++ 20 std :: string fournira finalement starts_with et ends_with . On dirait qu’il ya une chance que, par c ++, 30 chaînes en c ++ puissent enfin devenir utilisables. Si vous ne lisez pas cela dans un avenir lointain, vous pouvez utiliser les commandes startsWith/endsWith:

#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 d'assistance 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 ne sont pas conçues pour être utilisées dans du code réel. Mais il y a un espoir que cela s'améliorera au moins.

26
Pavel

La méthode std::mismatch 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() );
25
xtofl

À mon avis, la solution la plus simple est la suivante:

bool endsWith(const string& s, const string& suffix)
{
    return s.rfind(suffix) == (s.size()-suffix.size());
}
10
Grzegorz Bazior

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 comparez-les à b (où n est la longueur de b)

Ou utilisez 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());
}
9
Dario

Permettez-moi d'étendre la solution de Joseph avec la version non sensible à 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);
        }
    );
}
3
PolarBear

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;
}
3
Ahmed Said

le même 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());
  }
2
dodjango

En ce qui concerne la réponse de Grzegorz Bazior. J'ai utilisé cette implémentation, mais l'original 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());
}
1
Andrew123

Si vous êtes comme moi et que vous n’aimez pas le purisme C++, voici un vieil hybride skool. Il y a un avantage lorsque les chaînes sont plus qu'une poignée de caractères, car la plupart des implémentations memcmp 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, elle présente un inconvénient, car elle ne prend pas en charge le mappage de caractères - par exemple, lorsque deux caractères ou plus 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;
}
0
jws

J'ai pensé qu'il était logique de poster 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 à la casse

// 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;
}
0
cute_ptr

une autre option consiste à utiliser regex. 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 si efficace, mais facile à mettre en œuvre.

0
Julien Pilet

Vérifiez si str a 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;
}
0
James Yang