OVH Cloud OVH Cloud

fonction C++ pour comparer deux string

62 réponses
Avatar
Geoffroy Baud
Bonjour,
existe-t-il dans les lib std
du C++ un moyen pour comparer deux
string, et que le test sois case
insensitive ?

if ( "NAME" == "name" )
return TRUE;


merci


--
-------------------------------------------------------------------
Geoffroy Baud geoffroy.baud@wanadoo.fr
0AE5 7A1B 527D 3966 8EBE 2EC0 AA79 EB54 7D7D 7CEC
-------------------------------------------------------------------

10 réponses

1 2 3 4 5
Avatar
James Kanze
Geoffroy Baud writes:

|> existe-t-il dans les lib std du C++ un moyen pour comparer deux
|> string, et que le test sois case insensitive ?

|> if ( "NAME" == "name" )
|> return TRUE;

std::locale( "le locale adéquate" )( chaine1, chaine2 )

est sensé faire l'affaire (vue que la comparaison ne peut pas se
faire de façon indépendamment du locale). Elle renvoie vrai si
chaine1 est inférieure à chaine2 ; il faut donc l'appeler deux
fois pour l'égalité. Si tu as à le faire souvent, régarde du
côté de la facette « collate ».

Aussi, il n'y a rien qui garantie que l'implémentation contient un
locale qui convient.

--
James Kanze mailto:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France +33 1 41 89 80 93
Avatar
Fabien LE LEZ
On 21 Sep 2003 13:12:35 +0200, James Kanze
wrote:

Aussi, il n'y a rien qui garantie que l'implémentation contient un
locale qui convient.


Et quid si on se limite au jeu de caractères ASCII (en gros, les
lettres non accentuées) ?

--
Let's face it, boys: the Trash Heap _is_ all.
-- the Trash Heap, Fraggle Rock, ep 1

Avatar
Michaël Monerau
Geoffroy Baud wrote:
Bonjour,


Bonjour,

existe-t-il dans les lib std
du C++ un moyen pour comparer deux
string, et que le test sois case
insensitive ?


Voilà une fonction que j'ai écrite (avec l'aide d'un exemple du Stroustrup)
:

// retourne -1 si s1 est moins longue que s2
// (mais égale dans ce qu'elle contient)

// et retourne 1 si s1 est plus longue que s2

// retourne 0 si les deux chaines sont identiques (en NoCase)
// (mais égale dans ce qu'elle contient)

int CMP_NoCase (const std::string& s1, const std::string& s2)
{
std::string::const_iterator p1 = s1.begin();
std::string::const_iterator p2 = s2.begin();
while (p1 != s1.end() && p2 != s2.end())
{
if (toupper (*p1) != toupper (*p2))
return (toupper (*p1) <
toupper (*p2)) ? -1 : 1;
++p1;
++p2;
}

return (s2.size() == s1.size()) ? 0 : (s1.size() < s2.size()) ? -1 : 1;
}

La mise en page est peut-être un peu archaïque, désolé. "toupper" (prononcer
"toupet" :p) fait partie de la lib C (donc #include <string.h>). Tu peux
cependant utiliser std::toupper, mais il faut un locale comme deuxième
argument, chose que je ne connais pas encore :o)

Si les deux chaînes sont différentes, -1 ou 1 est retourné selon si le
premier caractère trouvé différent est supérieur à l'autre. C'est peut-être
à changer (-2 et 2) pour mieux savoir pourquoi les deux chaines de
caractères étaient différentes... Mais bon, je n'en ai pas eu le besoin.
J'utilise seulement pour savoir si deux chaînes sont identiques ou non.

merci


De rien.
--
<=- Michaël "Cortex" Monerau -=>

Avatar
Fabien LE LEZ
On 21 Sep 2003 18:16:28 +0200, James Kanze
wrote:

|> Et quid si on se limite au jeu de caractères ASCII (en gros, les
|> lettres non accentuées) ?

C-à-d qu'on ne supporte ni l'anglais ni le français ?


Mais on supporte un langage de script non-case-sensitive (le Basic par
exemple).

--
Let's face it, boys: the Trash Heap _is_ all.
-- the Trash Heap, Fraggle Rock, ep 1

Avatar
James Kanze
Fabien LE LEZ writes:

|> On 21 Sep 2003 18:16:28 +0200, James Kanze
|> wrote:

|> >|> Et quid si on se limite au jeu de caractères ASCII (en gros,
|> >|> les lettres non accentuées) ?

|> >C-à-d qu'on ne supporte ni l'anglais ni le français ?

|> Mais on supporte un langage de script non-case-sensitive (le Basic
|> par exemple).

Pas avec la bibliothèque standard:-). On ne supporte même pas la
comparaison des noms de fichier Windows.

En fait, le C++ dérive du C, qui est né dans l'univers de Unix.
Tant qu'on reste dans l'univers de Unix, tout va bien. Dès qu'on en
sort, ne serait-ce que pour accepter du texte avec des accents, il faut
connaître des pièges.

À titre d'exemple : tu donnes un fichier avec les noms des villes du
banlieu parisien à un programme écrit en C. Il y en aurait pas mal
qui s'arrête pile au milieu de la ligne avec Le-Haÿ-des-Roses.

--
James Kanze mailto:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France +33 1 41 89 80 93
Avatar
Fabien LE LEZ
On 21 Sep 2003 18:42:59 +0200, James Kanze
wrote:

|> Mais on supporte un langage de script non-case-sensitive (le Basic
|> par exemple).

Pas avec la bibliothèque standard:-). On ne supporte même pas la
comparaison des noms de fichier Windows.


Uh ?
Pour les noms de fichiers Windows, je comprends (Dès qu'on met des
accents, même moi je ne comprends pas comment ça marche, surtout quand
on travaille en ligne de commande, avec le jeu de caractères OEM).
Par contre, pour le Basic, dont les commandes (case-insensitive) ne
sont constituées que de lettres non-accentuées (et éventuellement de
chiffres), je m'étonne que le C ou le C++ ne sachent pas gérer la
comparaison sans casse.

--
Let's face it, boys: the Trash Heap _is_ all.
-- the Trash Heap, Fraggle Rock, ep 1

Avatar
Michaël Monerau
James Kanze wrote:
int CMP_NoCase (const std::string& s1, const std::string& s2)
{
std::string::const_iterator p1 = s1.begin();
std::string::const_iterator p2 = s2.begin();
while (p1 != s1.end() && p2 != s2.end())
{
if (toupper (*p1) != toupper (*p2))
return (toupper (*p1) <
toupper (*p2)) ? -1 : 1;



Tu rémarques que sur la plupart des implémentations, le code
ci-dessus est bourré des comportements indéfinis. Tu ne peux pas
passer un char à toupper.


Ah, je ne savais pas... Sur mon VC 7.1, ça fonctionne, mais je veux bien
croire que ce ne serait pas le cas partout.
Mais alors, comment expliques-tu le code issu du Stroustrup :

p.591, §20.3.8 :
#### début citation
for example, the 'toupper' function (§20.4.2) allows us to write
case-insensitive comparisons :

using namespace std;
int cmp_nocase (const string& s, const string& s2)
{
string::const_iterator p = s.begin ();
string::const_iterator p2 = s2.begin ();

while (p != s.end() && p2 != s2.end)
{
if (toupper(*p) != toupper (*p2))
// blah blah blah

// ...
}
#### fin citation

Stroustrup aurait écrit quelque chose non conforme ?

Et au 20.4.2, on a :
#### citation
In <ctype.h> and <cctype>, the standard library provides a set of useful
functions for dealing with ASCII and similar characters sets :

** liste des fonctions **
int toupper (int c); // uppercase equivalent to c
int tolower (int c); // lowercase equivalent to c
#### fin citation

Par contre, là, pourquoi utiliser un int, je ne sais pas trop... (pour
autoriser des caractères sur plusieurs octets plus tard ?) Mais c'est le cas
de toutes les fonctions 'is*' (come isalpha, isupper, etc...). Et je doute
qu'utiliser une de ces fonctions en C++ avec un argument char (qui sera donc
converti en int) soit implementation-defined... Sinon, à quoi serviraient
ces fonctions ?

La mise en page est peut-être un peu archaïque, désolé.
"toupper" (prononcer "toupet" :p) fait partie de la lib C (donc
#include <string.h>).



Non seulement il font partie de la lib C, il ne prenent pas ce char
comme paramètre, et le lui en passer donne un comportement
indéfini.


Pourquoi ? une conversion char -> int n'est pas bien compliqué ?! Enfin, je
ne connais pas ce domaine...

Tu peux cependant utiliser std::toupper, mais il faut un locale
comme deuxième argument, chose que je ne connais pas encore :o)



C'est nettement mieux, parce que le premier paramètre est bien un
char, et non un int avec une portée restreinte qui ne comprend pas
toutes les valeurs d'un char.

En revanche, ça pose un problème de portabilité : <locale>
n'existe que sur un des trois compilateurs qu'on utilise où je
travaille, par exemple.

Note que quoique tu fasses, le résultat dépendra d'un locale.


OK. Mais alors, comment faire un cmp_nocase en C++ portable ? Ne me dis pas
que c'est impossible !!! ;-)
--
<=- Michaël "Cortex" Monerau -=>



Avatar
Gabriel Dos Reis
James Kanze writes:

| qui s'arrête pile au milieu de la ligne avec Le-Haÿ-des-Roses.

parce que le nom de la vile est incorrecte ? ;-p

-- Gaby
Avatar
James Kanze
Fabien LE LEZ writes:

|> On 21 Sep 2003 18:42:59 +0200, James Kanze
|> wrote:

|> >|> Mais on supporte un langage de script non-case-sensitive (le
|> >|> Basic par exemple).

|> >Pas avec la bibliothèque standard:-). On ne supporte même pas
|> >la comparaison des noms de fichier Windows.

|> Uh ?
|> Pour les noms de fichiers Windows, je comprends (Dès qu'on met
|> des accents, même moi je ne comprends pas comment ça marche,
|> surtout quand on travaille en ligne de commande, avec le jeu de
|> caractères OEM). Par contre, pour le Basic, dont les commandes
|> (case-insensitive) ne sont constituées que de lettres
|> non-accentuées (et éventuellement de chiffres), je m'étonne
|> que le C ou le C++ ne sachent pas gérer la comparaison sans
|> casse.

C'est cependant vrai. Il n'existe aucune comparaison de chaîne de
caractères qui ignore la case, en dehors des locales facultatifs.

--
James Kanze mailto:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France +33 1 41 89 80 93
Avatar
Fabien LE LEZ
On 21 Sep 2003 21:04:44 +0200, James Kanze
wrote:

Il n'existe aucune comparaison de chaîne de
caractères qui ignore la case, en dehors des locales facultatifs.


Y'a pas à dire, le C++, c'est de la merde ! ;-)
Au fait, existe-t-il des systèmes où les 52 lettres ([A-Za-z]) ne sont
pas (toutes) présentes ?

--
Let's face it, boys: the Trash Heap _is_ all.
-- the Trash Heap, Fraggle Rock, ep 1

1 2 3 4 5