son - string compare c++
¿Cómo comparar los extremos de las cadenas en C? (17)
Código probado, incluye la prueba:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int ends_with_foo(const char *str)
{
char *dot = strrchr(str, ''.'');
if (NULL == dot) return 0;
return strcmp(dot, ".foo") == 0;
}
int main (int argc, const char * argv[])
{
char *test[] = { "something", "anotherthing.foo" };
int i;
for (i = 0; i < sizeof(test) / sizeof(char *); i++) {
printf("''%s'' ends %sin ''.foo''/n",
test[i],
ends_with_foo(test[i]) ? "" : "not ");
}
return 0;
}
Quiero asegurarme de que mi cadena termine con ".foo". Estoy usando C, un idioma con el que no estoy totalmente familiarizado. La mejor manera que he encontrado para hacerlo es a continuación. ¿Algún gurú de C quiere asegurarse de que estoy haciendo esto de manera elegante y sabia?
int EndsWithFoo(char *str)
{
if(strlen(str) >= strlen(".foo"))
{
if(!strcmp(str + strlen(str) - strlen(".foo"), ".foo"))
{
return 1;
}
}
return 0;
}
Lo haría así:
/**
* Return 0 if the string haystack ends with the string needle
*
* @param haystack the string to be analyzed
* @param needle the suffix string
* @return 0 if the string haystack ends with the string needle, 1 if not
*/
int strbcmp(const char *haystack, const char *needle) {
int length;
if (haystack && needle && strlen(haystack) >= (length = strlen(needle)) && strlen(strstr(haystack, needle)) == length) return 0;
return 1;
}
El programa de prueba es:
#include <stdio.h>
#include <string.h>
int strbcmp(const char *haystack, const char *needle) {
int length;
if (haystack && needle && strlen(haystack) >= (length = strlen(needle)) && strlen(strstr(haystack,needle)) == length) return 0;
return 1;
}
int main (int argc, char * argv[]){
char *a = "file1.gz";
char *b = "1.gz";
char *c = NULL;
char *d = "1.gzabc";
printf("%s %s = %d/n",a,b,strbcmp(a,b));
printf("%s %s = %d/n",a,c,strbcmp(a,c));
printf("%s %s = %d/n",d,b,strbcmp(d,b));
return 0;
}
Lo siento, llegué un poco tarde a la fiesta. ¿No podrías hacer algo con algunas matemáticas de puntero simple?
char* str = "hello.foo"; //this would be string given
int x = 4; //.foo has 4 characters
int n = strlen(str)- x; //where x is equal to suffix length
char* test = &str[n]; //do some pointer math to find the last characters
if(strcmp(test, ".foo") == 0){
//do some stuff
}// end if
Los punteros de caracteres funcionan apuntando al primer personaje de su matriz. Entonces, cuando haces esto, estableces el primer carácter de la prueba como ''.'' en ''.foo'' (si eso es lo que contiene). También es por eso que no necesita asignar memoria, ya que solo apunta a la matriz de caracteres ya existente.
Los strlen(".foo")
s no son necesarios. Si realmente deseaba tenerlo flexible, podría usar sizeof ".foo" - 1
- una constante de tiempo de compilación.
Además, una verificación de cadena nula sería buena.
Me gustaría usar mi versión:
bool endsWith(const char *filename, const char *ext) {
const uint len = strlen(filename);
const uint extLen = strlen(ext);
if (len < extLen) {
return false;
}
for (uint index = 1; index <= extLen; index++) {
if (filename[len - index] != ext[extLen - index]) {
return false;
}
}
return true;
}
No llame a strlen más de una vez por cadena.
int EndsWith(const char *str, const char *suffix)
{
if (!str || !suffix)
return 0;
size_t lenstr = strlen(str);
size_t lensuffix = strlen(suffix);
if (lensuffix > lenstr)
return 0;
return strncmp(str + lenstr - lensuffix, suffix, lensuffix) == 0;
}
int EndsWithFoo(const char *str) { return EndsWith(str, ".foo"); }
EDITAR: se agregó un control NULL para el pedante. Para el ultrapedante, debata si debe volverse distinto de cero si tanto str como sufijo son ambos NULL.
No tengo acceso a un compilador en este momento, ¿podría alguien decirme si esto funciona?
#include <stdio.h>
#include <string.h>
int EndsWithFoo(const char* s);
int
main(void)
{
printf("%d/n", EndsWithFoo("whatever.foo"));
return 0;
}
int EndsWithFoo(const char* s)
{
int ret = 0;
if (s != NULL)
{
size_t size = strlen(s);
if (size >= 4 &&
s[size-4] == ''.'' &&
s[size-3] == ''f'' &&
s[size-2] == ''o'' &&
s[size-1] == ''o'')
{
ret = 1;
}
}
return ret;
}
De todos modos, asegúrese de calificar el parámetro como const
, le dice a todos (incluido el compilador) que no tiene la intención de modificar la cadena.
Si puede cambiar la firma de su función, intente cambiarla a
int EndsWith(char const * str, char const * suffix, int lenstr, int lensuf);
Esto dará como resultado un código más seguro, más reutilizable y más eficiente:
- Los calificadores const agregados se asegurarán de no alterar por error las cadenas de entrada. Esta función es un predicado, así que supongo que nunca debe tener efectos secundarios.
- El sufijo para comparar se pasa como un parámetro, por lo que puede guardar esta función para su posterior reutilización con otros sufijos.
- Esta firma te dará la oportunidad de pasar los largos de las cuerdas si ya las conoces. Llamamos a esto programación dinámica .
Podemos definir la función así:
int EndsWith(char const * str, char const * suffix, int lenstr, int lensuf)
{
if( ! str && ! suffix ) return 1;
if( ! str || ! suffix ) return 0;
if( lenstr < 0 ) lenstr = strlen(str);
if( lensuf < 0 ) lensuf = strlen(suffix);
return strcmp(str + lenstr - lensuf, suffix) == 0;
}
El contraargumento obvio para los parámetros adicionales es que implican más ruido en el código o un código menos expresivo.
Si siempre hay algo más allá del punto, podríamos permitirnos algo de aritmética del puntero:
int EndsWithFoo (char *str)
{
int iRetVal = 0;
char * pchDot = strrchr (str, ''.'');
if (pchDot)
{
if (strcmp (pchDot+1, "foo") == 0)
{
iRetVal = 1;
}
}
return iRetVal;
}
Por supuesto, es probable que desee agregar un poco de tensión allí para comprobar que hay algo más allá del punto :-)
NB - No ejecuté esto para verificarlo, pero me parece bien.
Siempre controlo las funciones de cadenas flexibles, tienen todo tipo de bits útiles. Ya existe una función de comprobación de sufijos.
gchar * str;
if (!g_str_has_suffix(str)) {
return FALSE;
}
Soy un poco nuevo en C, así que me disculpo si esto no es 100% ... ¡pero parece una cláusula de guardia sólida para mí!
Solución general con un strlen (aguja), strstr () y prueba para ''/ 0'':
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
bool endsWith(const char* haystack, const char* needle)
{
bool rv = false;
if (haystack && needle)
{
size_t needle_size = strlen(needle);
const char* act = haystack;
while (NULL != (act = strstr(act, needle)))
{
if (*(act + needle_size) == ''/0'')
{
rv = true;
break;
}
act += needle_size;
}
}
return rv;
}
int main (int argc, char * argv[])
{
char *a = "file1.gz";
char *b = "1.gz";
char *c = NULL;
char *d = "1.gzabc";
char *e = "1.gzabc1.gz";
printf("endsWith:/n");
printf("%s %s = %d/n",a,b,endsWith(a,b));
printf("%s NULL = %d/n",a,endsWith(a,c));
printf("%s %s = %d/n",d,b,endsWith(d,b));
printf("%s %s = %d/n",e,b,endsWith(e,b));
return 0;
}
Sugeriría que la mejor manera de hacerlo es invertir la secuencia y luego comparar los primeros n caracteres.
Hay muchos ejemplos de funciones de inversión de cadenas (incluso Joel lo cita como una pregunta de entrevista estándar), así que simplemente implemente uno de esos pasos para comparar las cadenas invertidas.
EDIT en respuesta a downvotes. De acuerdo, sí, este enfoque requiere una CPU o memoria adicional para implementar, pero el que pregunta no indica ninguna de esas restricciones y explícitamente pidió una solución elegante. Invertir las cuerdas y luego compararlas desde el frente es mucho más elegante que perder el tiempo buscando el final de las cuerdas y trabajando hacia atrás. Y es mucho más fácil para el próximo programador captar y mantener también.
Tal vez...
bool endswith (const char* str, const char* tail)
{
const char* foo = strrstr (str, tail);
if (foo)
{
const int strlength = strlen (str);
const int taillength = strlen (tail);
return foo == (str + strlength - taillength);
}
return false;
}
endswith (str, ".foo");
Por cierto, la solución en la pregunta original se ve bien aparte de las llamadas strlen repetidas.
También puedes generalizar de esta manera:
int endsWith(const char* text, const char* extn)
{
int result = 1;
int len = strlen(text);
int exprLen = strlen(extn);
int index = len-exprLen;
int count = 0;
if(len > exprLen)
{
for( ; count < exprLen; ++count)
{
if(text[index + count] != extn[count])
{
result = 0;
break;
}
}
}
else
{
result = 0;
}
return result;
}
#include <assert.h>
#include <string.h>
int string_has_suffix(const char *str, const char *suf)
{
assert(str && suf);
const char *a = str + strlen(str);
const char *b = suf + strlen(suf);
while (a != str && b != suf) {
if (*--a != *--b) break;
}
return b == suf && *a == *b;
}
// Test Unit
int main (int argc, char *argv[])
{
assert( string_has_suffix("", ""));
assert(!string_has_suffix("", "a"));
assert( string_has_suffix("a", ""));
assert( string_has_suffix("a", "a"));
assert(!string_has_suffix("a", "b"));
assert(!string_has_suffix("a", "ba"));
assert( string_has_suffix("abc", "abc"));
assert(!string_has_suffix("abc", "eeabc"));
assert(!string_has_suffix("abc", "xbc"));
assert(!string_has_suffix("abc", "axc"));
assert(!string_has_suffix("abcdef", "abcxef"));
assert(!string_has_suffix("abcdef", "abxxef"));
assert( string_has_suffix("b.a", ""));
assert( string_has_suffix("b.a", "a"));
assert( string_has_suffix("b.a", ".a"));
assert( string_has_suffix("b.a", "b.a"));
assert(!string_has_suffix("b.a", "x"));
assert( string_has_suffix("abc.foo.bar", ""));
assert( string_has_suffix("abc.foo.bar", "r"));
assert( string_has_suffix("abc.foo.bar", "ar"));
assert( string_has_suffix("abc.foo.bar", "bar"));
assert(!string_has_suffix("abc.foo.bar", "xar"));
assert( string_has_suffix("abc.foo.bar", ".bar"));
assert( string_has_suffix("abc.foo.bar", "foo.bar"));
assert(!string_has_suffix("abc.foo.bar", "xoo.bar"));
assert(!string_has_suffix("abc.foo.bar", "foo.ba"));
assert( string_has_suffix("abc.foo.bar", ".foo.bar"));
assert( string_has_suffix("abc.foo.bar", "c.foo.bar"));
assert( string_has_suffix("abc.foo.bar", "abc.foo.bar"));
assert(!string_has_suffix("abc.foo.bar", "xabc.foo.bar"));
assert(!string_has_suffix("abc.foo.bar", "ac.foo.bar"));
assert( string_has_suffix("abc.foo.foo", ".foo"));
assert( string_has_suffix("abc.foo.foo", ".foo.foo"));
assert( string_has_suffix("abcdefgh", ""));
assert(!string_has_suffix("abcdefgh", " "));
assert( string_has_suffix("abcdefgh", "h"));
assert( string_has_suffix("abcdefgh", "gh"));
assert( string_has_suffix("abcdefgh", "fgh"));
assert(!string_has_suffix("abcdefgh", "agh"));
assert( string_has_suffix("abcdefgh", "abcdefgh"));
return 0;
}
// $ gcc -Wall string_has_suffix.c && ./a.out
int EndsWithFoo( char *string )
{
string = strrchr(string, ''.'');
if( string != NULL )
return( strcmp(string, ".foo") );
return( -1 );
}
Devolverá 0 si termina con ".foo".
int strends(char* str, char* end){
return strcmp(str + strlen(str) - strlen(end), end) == 0;
}
Encontré que esta es la forma más simple de lograr el resultado.