Je veux m'assurer que ma chaîne se termine par ".foo". J'utilise C, un langage que je ne connais pas totalement. La meilleure façon que j'ai trouvée de le faire est ci-dessous. Tous les gourous du C veulent s’assurer que je le fais avec élégance et sagesse?
int EndsWithFoo(char *str)
{
if(strlen(str) >= strlen(".foo"))
{
if(!strcmp(str + strlen(str) - strlen(".foo"), ".foo"))
{
return 1;
}
}
return 0;
}
N'appelez pas strlen plus d'une fois par chaîne.
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"); }
EDIT: ajout d'une vérification NULL pour le pédant. Pour l'ultra pédant, discutez s'il doit renvoyer non nul si str et le suffixe sont tous deux NULL.
int EndsWithFoo( char *string )
{
string = strrchr(string, '.');
if( string != NULL )
return( strcmp(string, ".foo") );
return( -1 );
}
Retourne 0 si se termine par ".foo".
Je n'ai pas accès à un compilateur pour le moment, alors quelqu'un pourrait-il me dire si cela fonctionne?
#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;
}
Quoi qu'il en soit, veillez à qualifier le paramètre par const
, il indique à tout le monde (y compris le compilateur) que vous n'avez pas l'intention de modifier la chaîne.
Si vous pouvez modifier la signature de votre fonction, essayez de la remplacer par
int EndsWith(char const * str, char const * suffix, int lenstr, int lensuf);
Cela se traduira par un code plus sûr, plus réutilisable et plus efficace:
Nous pouvons définir la fonction comme suit:
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;
}
Le contre-argument évident pour les paramètres supplémentaires est qu'ils impliquent plus de bruit dans le code, ou un code moins expressif.
Les strlen(".foo")
s ne sont pas nécessaires. Si vous voulez vraiment le rendre flexible, vous pouvez utiliser sizeof ".foo" - 1
- une constante de temps de compilation.
En outre, une vérification de chaîne nulle serait bien.
Le code testé inclut le test:
#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;
}
Désolé, je suis un peu en retard à la fête. Ne pourriez-vous pas faire quelque chose avec un calcul mathématique 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
Les pointeurs de caractères fonctionnent en pointant sur le premier caractère de leur tableau. Ainsi, lorsque vous faites cela, vous définissez le premier caractère du test comme le "." dans '.foo' (si c'est ce qu'il contient). C'est aussi pourquoi vous n'avez pas besoin d'allouer de mémoire car c'est juste le tableau de caractères existant.
Peut être...
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");
Soit dit en passant, la solution proposée dans la question initiale n’est pas différente des appels strlen répétés.
Je vérifie toujours les fonctions de chaîne de Glib, elles ont toutes sortes de bits utiles. Une fonction de vérification de suffixe existe déjà.
gchar * str;
if (!g_str_has_suffix(str)) {
return FALSE;
}
Je suis un peu nouveau chez C, alors je m'excuse si ce n'est pas à 100% ... mais ça ressemble à une solide clause de garde!
S'il y a toujours quelque chose au-delà du point, nous pourrions nous livrer à une arithmétique de pointeur:
int EndsWithFoo (char *str)
{
int iRetVal = 0;
char * pchDot = strrchr (str, '.');
if (pchDot)
{
if (strcmp (pchDot+1, "foo") == 0)
{
iRetVal = 1;
}
}
return iRetVal;
}
Bien sûr, vous voudrez probablement ajouter un peu de strlen à vérifier ici est quelque chose au-delà du point :-)
NB - Je n'ai pas vérifié cela, mais ça me semble correct.
Vous pouvez aussi généraliser comme ceci:
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;
}
Pas si différent de cette question, à propos du test d’un suffixe de chaîne:
Comment puis-je vérifier si une chaîne se termine par ".csv" en C
Solution générale avec un strlen (aiguille), strstr () et testez '\ 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;
}
#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
C'est la réponse la plus efficace (pour un ordinateur) que vous trouverez ici.
int endsWith(const char *string,const char *tail)
{
const char *s1;
const char *s2;
if (!*tail)
return 1;
if (!*string)
return 0;
for (s1 = string; *s1; ++s1);
for (s2 = tail; *s2; ++s2);
if (s1 - string < s2 - tail)
return 0;
for (--s1, --s2; *s1 == *s2 && s2 >= tail; --s1, --s2);
if (s2 < tail)
return 1;
else
return 0;
}
Je voudrais utiliser ma version:
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;
}