Autres pièges à éviter lorsque vous effectuez des comparaisons sans tenir compte de la casse :
Comparer en minuscules ou en majuscules ? (question assez courante)
Les deux ci-dessous renverront 0 avec strcicmpL("A", "a")
et strcicmpU("A", "a")
.
Pourtant, strcicmpL("A", "_")
et strcicmpU("A", "_")
peut retourner des résultats signés différents comme '_'
se trouve souvent entre les majuscules et les minuscules.
Cela affecte l'ordre de tri lorsqu'il est utilisé avec qsort(..., ..., ..., strcicmp)
. Les fonctions de la bibliothèque C non standard, comme les fonctions courantes de stricmp()
ou strcasecmp()
ont tendance à être bien définis et favorisent la comparaison avec les minuscules. Pourtant, des variations existent.
int strcicmpL(char const *a, char const *b) {
while (*b) {
int d = tolower(*a) - tolower(*b);
if (d) {
return d;
}
a++;
b++;
}
return tolower(*a);
}
int strcicmpU(char const *a, char const *b) {
while (*b) {
int d = toupper(*a) - toupper(*b);
if (d) {
return d;
}
a++;
b++;
}
return toupper(*a);
}
char
peut avoir une valeur négative. (pas rare)
touppper(int)
et tolower(int)
sont spécifiés pour unsigned char
et les valeurs négatives EOF
. Plus loin, strcmp()
renvoie les résultats comme si chaque char
a été converti en unsigned char
indépendamment du fait que char
est signé ou non signé .
tolower(*a); // Potential UB
tolower((unsigned char) *a); // Correct (Almost - see following)
char
peut avoir une valeur négative et ne pas être un complément à 2. (rare)
Ce qui précède ne traite pas -0
ni d'autres valeurs négatives correctement car le motif binaire doit être interprété comme unsigned char
. Pour gérer correctement tous les codages d'entiers, changez d'abord le type de pointeur.
// tolower((unsigned char) *a);
tolower(*(const unsigned char *)a); // Correct
Locale (moins fréquent)
Bien que les jeux de caractères utilisant le code ASCII (0-127) soient omniprésents, les codes restants tendent à avoir locale des questions spécifiques. Ainsi, strcasecmp("\xE4", "a")
peut retourner un 0 sur un système et un non-zéro sur un autre.
Unicode (la voie de l'avenir)
Si une solution doit gérer plus que l'ASCII, il faut envisager un module unicode_strcicmp()
. Comme la bibliothèque C ne fournit pas une telle fonction, il est recommandé d'utiliser une fonction précodée provenant d'une autre bibliothèque. Écrire votre propre unicode_strcicmp()
est une tâche décourageante.
Est-ce que toutes les lettres correspondent à un bas et à un haut ? (pédant)
[A-Z] s'applique de manière univoque à [a-z], pourtant divers locales font correspondre divers caractères minuscules à un caractère supérieur et vice-versa. En outre, certains caractères majuscules peuvent ne pas avoir d'équivalent en minuscules et vice-versa.
Cela oblige le code à couvrir à la fois tolower()
et tolower()
.
int d = tolower(toupper(*a)) - tolower(toupper(*b));
Encore une fois, des résultats potentiellement différents pour le tri si le code a fait tolower(toupper(*a))
vs. toupper(tolower(*a))
.
Portabilité
@B. Nadolson recommande d'éviter de rouler votre propre strcicmp()
et cela est raisonnable, sauf lorsque le code a besoin d'une fonctionnalité portable équivalente élevée.
Vous trouverez ci-dessous une approche qui est même plus rapide que certaines fonctions fournies par le système. Elle ne fait qu'une seule comparaison par boucle au lieu de deux en utilisant 2 tables différentes qui diffèrent avec '\0'
. Vos résultats peuvent varier.
static unsigned char low1[UCHAR_MAX + 1] = {
0, 1, 2, 3, ...
'@', 'a', 'b', 'c', ... 'z', `[`, ... // @ABC... Z[...
'`', 'a', 'b', 'c', ... 'z', `{`, ... // `abc... z{...
}
static unsigned char low2[UCHAR_MAX + 1] = {
// v--- Not zero, but A which matches none in `low1[]`
'A', 1, 2, 3, ...
'@', 'a', 'b', 'c', ... 'z', `[`, ...
'`', 'a', 'b', 'c', ... 'z', `{`, ...
}
int strcicmp_ch(char const *a, char const *b) {
// compare using tables that differ slightly.
while (low1[*(const unsigned char *)a] == low2[*(const unsigned char *)b]) {
a++;
b++;
}
// Either strings differ or null character detected.
// Perform subtraction using same table.
return (low1[*(const unsigned char *)a] - low1[*(const unsigned char *)b]);
}
0 votes
Je pense que j'ai mal écrit cela, postcode n'est pas un type, juste la valeur réelle que le char* va contenir.
3 votes
Sur quelle plateforme êtes-vous ? De nombreuses plateformes disposent d'une fonction spécifique pour ce faire.
0 votes
Si vous comparez un chiffre avec une lettre, vous savez que les chaînes ne sont pas équivalentes, quelle que soit la casse.
0 votes
Je suppose que vous voulez simplement parler de la comparaison de chaînes de caractères ASCII ? Il ne s'agit pas d'une comparaison générique à l'échelle mondiale dans plusieurs langues ?
0 votes
La comparaison pourrait aboutir à la comparaison d'un chiffre et d'une lettre. Je dois tester si deux codes postaux sont égaux l'un à l'autre, si l'un est supérieur ou inférieur à l'autre. La partie supérieure à, inférieure à est déroutante, je ne suis pas sûr de savoir comment cela va fonctionner.