2009-05-17 22 views

Respuesta

8

Deje a ser una cadena y b la cadena que busca. Utilice a.substr para obtener los últimos n caracteres de a y compararlos con b (donde n es la longitud de b)

O utilice std::equal (incluyen <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()); 
} 
+0

¿Cómo puedo devolver cierto también si termina después de mi cadena con \ n o r o \ tanto ??? gracias! – sofr

+0

@Dario: Su solución usando std :: equal() es buena, la que usa substr() no tanto, a menos que esté usando cadenas COW (y creo que pocas personas), substr() implica crear un segundo copia de una parte de la cadena, lo que implica que la asignación de memoria dinámica está involucrada. Esto puede fallar y, en cualquier caso, significa que se usa más memoria que otras soluciones (y es casi seguro que es más lenta que otras soluciones). –

165

comparar simplemente el último 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; 
} 
+0

Sí, esta es la mejor manera de hacerlo, sin duda. – Noldorin

+0

¡Muy bien! Me encanta este tipo de métodos ... – Milan

+0

Lo intenté pero de alguna manera no funcionó Necesito mi código también para manejar si después de la terminación tiene \ r o \ n etc. gracias por la ayuda – sofr

3

puede utilizar string::rfind

El Ejemplo completo basado en los 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; 
} 
+2

-1.Sí, podría usarlo, pero es innecesariamente lento en el caso de que la cadena no termine con el final proporcionado; el escaneo continuará hasta el comienzo de la cadena. Además, no mencionas que necesitas una prueba posterior para asegurarte de que el final coincide con ** al final de la cadena **, en lugar de hacerlo en otra parte de la cadena. –

+0

Acabo de poner el enlace de la función necesaria y creo que es muy fácil hacerlo desde la documentación str.rfind (key, str.length() - key.length(), key.length()); –

+0

OK, eso es eficiente, pero en ese caso, string :: find() funcionaría igual de bien. También debe mencionar el caso donde key.length()> str.length() - el código que sugiere en su comentario se bloqueará en este caso. Si actualiza su respuesta con esta información, dejaré mi -1. –

22

El método std::mismatch puede servir a 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()); 
+3

+1. Nunca antes había notado std :: mismatch(). Me pregunto qué más hay en ese archivo de encabezado de algoritmos que nunca he visto ... –

+3

Creo que vale la pena una pregunta ASÍ: ¿alguna vez has navegado? a través de las funciones STL disponibles? – xtofl

+1

Tenga en cuenta que esto tiene el mismo requisito que 'std :: equal': debe verificar con anticipación que el supuesto sufijo no es más largo que la cadena en la que lo está buscando. No tener en cuenta que conduce a un comportamiento indefinido. –

131

Utilice 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()); 
} 
+15

@Joseph, esta es claramente la respuesta correcta. Es elegante y fiel al espíritu de C++. Edité tu respuesta con la opinión de Ahmed, pero las mentes brillantes lo rechazaron. Aquí hay un enlace a mi edición: http://stackoverflow.com/review/suggested-edits/2790894 –

+3

Tenga en cuenta que a MSVC10 no le gusta esta solución: 'std :: equal (sufijo.rbegin(), sufijo.rend() , str.rbegin() 'En modo de depuración, arroja:' _DEBUG_ERROR ("iterador de cadena no decrementable"); ' –

122

Use boost::algorithm::ends_with (consulte p. Ej. 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)); 
36

Sé que la pregunta es para C++, pero si alguien necesita un buen ol función C para hacer esto' formaron;

 

/* 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); 
} 
 
6

En mi opinión más simple, la solución C++ es:

bool endsWith(const string& s, const string& suffix) 
{ 
    return s.rfind(suffix) == (s.size()-suffix.size()); 
} 
+3

Esto es bastante lento ya que buscará toda la cadena' s' en lugar de simplemente probar el final de la misma ! –

+0

@AlexisWilke ¿Lento? ¿Cuántos nanosegundos? – nodakai

+1

@nodakai, si tengo una cadena de 1Mb, va a ser mucho más que nanosegundos. –

1

En cuanto a Grzegorz Bazior respuesta. Usé esta implementación, pero la original tiene errores (devuelve verdadero si comparo "..." con ".so"). propongo función modificada:

bool endsWith(const string& s, const string& suffix) 
{ 
    return s.size() >= suffix.size() && s.rfind(suffix) == (s.size()-suffix.size()); 
} 
1

el mismo 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()); 
    } 
+1

¿Por qué 'starts_with' utiliza 'string :: compare'? ¿Por qué no' std :: equal (start.begin(), start.end(), str.begin()) ' ? –

+0

Solo porque starts_with fue el primero que necesité. Ends_with se agregó más tarde. – dodjango

0

Comprobar si str tiene sufijo, mediante el siguiente:

/* 
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

Pensé que tiene sentido publicar una solución sin formato que no utiliza ninguna función de la 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; 
} 

Añadiendo un simple std::tolower podemos hacer este caso 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; 
} 
6

Un montón de respuestas extrañas. Todos estos con rfind no son buenos.La solución que usa boost/algorithm/string está bien, pero prefiero mantenerme alejado de boost. std::equal es bueno, pero que acababa de mantener algo similar a una cuerda:

#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 cooperadoras 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)); 
} 

OMI, C++ cadenas son claramente disfuncional, y no fueron hechos para ser utilizado en el código del mundo real.

+0

Dado que str.compare no devuelve un booleano, no es tan inteligente probar "== 0" utilizando el operador not ("!"), Ya que puede ser confuso para los lectores. Utilice "... && str.compare (...) == 0" para mayor claridad. –

0

Si eres como yo y no tanto en el purismo C++, aquí tienes un viejo híbrido skool. Existe una ventaja cuando las cadenas son más que un puñado de caracteres, ya que la mayoría de las implementaciones de memcmp comparan palabras de máquina cuando es posible.

Debe tener el control del juego de caracteres. Por ejemplo, si este enfoque se usa con el tipo utf-8 o wchar, existe una desventaja, ya que no admite la asignación de caracteres; por ejemplo, cuando dos o más caracteres son logically identical.

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

Permítanme extender Joseph's solution con la versión de mayúsculas y minúsculas (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); 
     } 
    ); 
} 
Cuestiones relacionadas