Respuestas:
Simplemente compare los últimos n caracteres 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;
}
Utiliza esta función:
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 modo de depuración, arroja:_DEBUG_ERROR("string iterator not decrementable");
Uso boost::algorithm::ends_with
(ver, por ejemplo, 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));
Tenga en cuenta que a partir de c ++ 20 std :: string finalmente se proporcionará begin_with y ends_with . Parece que existe la posibilidad de que con c ++ 30 cadenas en c ++ finalmente puedan ser utilizables, si no está leyendo esto desde un futuro lejano, puede usar estos comienzos con / fines 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);
}
y algunas sobrecargas de ayuda adicionales:
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));
}
En mi opinión, las cadenas de c ++ son claramente disfuncionales, y no fueron hechas para usarse en el código del mundo real. Pero existe la esperanza de que esto mejore al menos.
Sé que la pregunta es para C ++, pero si alguien necesita una buena función de C para hacer esto:
/* 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 );
}
El std::mismatch
método puede cumplir este propósito cuando se utiliza para iterar hacia atrás desde el final de ambas cadenas:
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
: debe verificar de antemano que el supuesto sufijo no sea más largo que la cadena en la que lo está buscando. Si no se verifica eso, se genera un comportamiento indefinido.
En mi opinión, la solución más simple de C ++ es:
bool endsWith(const string& s, const string& suffix)
{
return s.rfind(suffix) == std::abs(s.size()-suffix.size());
}
s
lugar de solo probar el final!
std::string::size()
es una operación de tiempo constante; lo que no necesita strlen
.
Deje a
ser una cadena y b
la cadena que busca. Use a.substr
para obtener los últimos n caracteres de a
y compárelos con b (donde n es la longitud de b
)
O usar std::equal
(incluir <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());
}
Permítanme extender la solución de Joseph con la versión que no distingue entre mayúsculas y minúsculas ( demostración en línea )
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);
}
);
}
igual que el anterior, aquí está mi solución
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
Por qué usa 'string :: compare'? ¿Por qué no std::equal(start.begin(), start.end(), str.begin())
?
Otra opción es utilizar expresiones regulares. El siguiente código hace que la búsqueda sea insensible a mayúsculas / minúsculas:
bool endsWithIgnoreCase(const std::string& str, const std::string& suffix) {
return std::regex_search(str,
std::regex(std::string(suffix) + "$", std::regex_constants::icase));
}
Probablemente no tan eficiente, pero fácil de implementar.
puedes usar string :: rfind
El ejemplo completo basado en comentarios:
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;
}
Compruebe si str tiene sufijo , utilizando a continuación:
/*
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;
}
Utilice el algoritmo std :: equal de <algorithms>
con iteración inversa:
std::string LogExt = ".log";
if (std::equal(LogExt.rbegin(), LogExt.rend(), filename.rbegin())) {
…
}
Respecto a la respuesta de Grzegorz Bazior. Usé esta implementación, pero la original tiene un error (devuelve verdadero si comparo ".." con ".so"). Propongo una función modificada:
bool endsWith(const string& s, const string& suffix)
{
return s.size() >= suffix.size() && s.rfind(suffix) == (s.size()-suffix.size());
}
Pensé que tenía sentido publicar una solución en bruto que no usa ninguna función de biblioteca ...
// 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;
}
Agregando un simple std::tolower
podemos hacer que este caso sea 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;
}
Encontré esta buena respuesta al problema similar "startWith":
Puede adoptar la solución para buscar solo en el último lugar de la cadena:
bool endsWith(const std::string& stack, const std::string& needle) {
return stack.find(needle, stack.size() - needle.size()) != std::string::npos;
}
De esta manera, puede hacerlo corto, rápido, usar c ++ estándar y hacerlo legible.
Si eres como yo y no te gusta el purismo de C ++, aquí hay un viejo híbrido skool. Hay una ventaja cuando las cadenas son más que un puñado de caracteres, como la mayoríamemcmp
implementaciones comparan palabras de máquina cuando es posible.
Debe tener el control del conjunto de caracteres. Por ejemplo, si este enfoque se usa con utf-8 o tipo wchar, hay alguna desventaja ya que no admitirá la asignación de caracteres, por ejemplo, cuando dos o más caracteres son lógicamente idénticos .
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;
}
Mis dos centavos:
bool endsWith(std::string str, std::string suffix)
{
return str.find(suffix, str.size() - suffix.size()) != string::npos;
}