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

Avatar
Samuel Krempp
le Tuesday 23 September 2003 16:34, écrivit :
C'est ce que j'ai proposé dans ma première réponse, mais on a eu le
problème avec le locale... Il n'y a malhereusement pas de fonction qui
passe comme ça un string en UpperCase :(


ceci-dit, si tu n'as pas été trop embrouillé par les réponses, tu auras
compris que c'est simplement par-ce que le concept même d' "uppercase"
d'une valeur n'a de sens que si l'on sait à quel caractère fait référence
cette valeur (ie qu'on a la bonne locale).

Si tu imposes à l'appelant de se restreindre aux caractères encodables avec
la locale C (qui est normalisée) et d'encoder les caractères de cette
façon, c'est tout à fait possible et très simple.

--
Sam

Avatar
Samuel Krempp
le Tuesday 23 September 2003 17:06,
écrivit :

Si tu imposes à l'appelant de se restreindre aux caractères encodables
avec la locale C (qui est normalisée) et d'encoder les caractères de cette
façon, c'est tout à fait possible et très simple.


tu peux d'ailleurs simplement imposer que la locale globale courante doit
correspondre à l'encodage utiliser dans le string passé. puis utiliser les
fonctions toupper de la locale en cours. C'est moins restreingant.
et à priori c'est un comportement assez naturel dans une fonction à qui l'on
ne précise pas de locale.

<locale> est expliqué par exemple dans l'appendix téléchargeable de
stroustrup
http://www.research.att.com/~bs/3rd_loc0.html

sur une plateforme ayant <locale>, on peut adatper le CMP_NoCase de
Michaël :

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

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


--
Sam

Avatar
kanze
"Michaël Monerau" wrote in message
news:<QOYbb.58146$...
Fabien LE LEZ wrote:
On 21 Sep 2003 22:03:33 +0200, James Kanze
wrote:

Au fait, existe-t-il des systèmes où les 52 lettres ([A-Za-z]) ne
sont pas (toutes) présentes ?



Italien.


Je parlais de systèmes informatiques. Existe-t-il réellement un OS
sur lequel les 52 lettres ne sont pas toutes présentes ? En d'autres
termes, l'implémentation suivante a-t-elle un comportement défini ?

char Majuscule (char n)
{
if (n=='a') return 'A';
else if (n=='b') return 'B';
...
else if (n=='z') return 'Z';
else return n;
}


Un switch n'est-il pas plus rapide ? (question dans l'absolu, pas
seulement pour cette fonction d'exemple ;-) ).


La solution classique quand le problème est aussi simple, c'est un
tableau :

char Majuscule( char n )
{
return majToMin[ static_cast< unsigned char >( n ) ] ;
}

L'avantage, évidemment, c'est que pour l'internationalisation, tu n'as
que lire le tableau du disque, selon la locale.

Dans le cas de wchar_t (32 bits sur ma bécane), où le tableau risque
être trop grand, j'utilise un hash_map dans mon implémentation.

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16





Avatar
kanze
"Ignace" wrote in message
news:<3f703935$0$27604$...
"Geoffroy Baud" a écrit dans le message de news:
3f6d7d45$0$10417$

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;


Moi j'ai trouvé une solution très bête en java. Je ne sais pas si elle
est valide en C++ : je fait subir le même changement de casse aux deux
éléments du test.

Metalangage (prétentieux):

if (str1.toUpper()==str2.toUpper()) ...


Tiens. En Java, je me serais plutôt servi de
java.lang.String.equalsIgnoreCase. Mais ça ne fait que cacher le
problème.

Il doit bien y avoir des conversions dans la stl et les classes string
non ? Comme ça, c'est le système qui se débrouille avec les locales.


Le problème, c'est qu'au fond, il n'y a pas de solution.

En allemand, par exemple, si j'ignore la case, je dois avoir "Fuß" = "FUSS". Ce que je ne sais pas faire en Java ; en C++, c'est précisement
le but des facettes std::collate.

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16


Avatar
Fabien LE LEZ
On Tue, 23 Sep 2003 14:31:12 GMT, "Michaël Monerau"
wrote:

Un switch n'est-il pas plus rapide ?


Peut-être, mais je voulais une implémentation où il n'y ait pas de
conversion (histoire de se concentrer sur le point qui m'intéressait).

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

Avatar
Michaël Monerau
Fabien LE LEZ wrote:
On Tue, 23 Sep 2003 14:31:12 GMT, "Michaël Monerau"
wrote:

Un switch n'est-il pas plus rapide ?


Peut-être, mais je voulais une implémentation où il n'y ait pas de
conversion (histoire de se concentrer sur le point qui m'intéressait).


?? Quelle conversion ?
--
<=- Michaël "Cortex" Monerau -=>


Avatar
Christophe Lephay
"Michaël Monerau" a écrit dans le message de
news:nz0cb.62981$
Fabien LE LEZ wrote:
Un switch n'est-il pas plus rapide ?


Peut-être, mais je voulais une implémentation où il n'y ait pas de
conversion (histoire de se concentrer sur le point qui m'intéressait).


?? Quelle conversion ?


switch, c'est avec les int, non ?

Chris



Avatar
Samuel Krempp
le Tuesday 23 September 2003 21:15, écrivit :

Ou dans la dernière édition ;-) que j'ai la chance d'avoir ! Mais j'en
suis quelques 100 pages avant...


argh. moi j'ai la 3°, et je suis très reconnaissant à Bjarne de fournir ses
appendixes.

sur une plateforme ayant <locale>, on peut adatper le CMP_NoCase de
Michaël :


C'est moi-même ;-)


quelle coincidence ! :-)


int CMP_NoCase
( const std::string& s1, const std::string& s2,
std::ctype<char> const & fac
= std::use_facet<std::ctype<char> >(std::locale() )
)
{
std::string::const_iterator p1 = s1.begin();
std::string::const_iterator p2 = s2.begin();
while (p1 != s1.end() && p2 != s2.end())
{
if (fac.toupper (*p1) != fac.toupper (*p2))
return (fac.toupper (*p1) <
fac.toupper (*p2)) ? -1 : 1;


Ah oui, d'accord... En fait, ça permet de contourner le problème du
toupper du C...
ben il vaut mieux utiliser les toupper C++ de toutes façon. effectivement,

ils ne posent pas les problèmes de conversion signée qu'a cette fonction
héritée du C.

la plus simple façon d'utiliser std::toupper pour remplacer celui du C dans
<string.h>, c'est std::toupper(*p1, std::locale())
Si on fournit une fonction de comparaison indépendante à la casse, autant
prendre la locale en argument.
(ah là j'ai mis la facet en argument, sans raison particulière)

En fait, le toupper du C correspondrait à :
// fac == std::use_facet<std::ctype<char> >(std::locale("C"))
fac.toupper (*p1);


si j'ai compris le toupper de string.h,
char c;
toupper(c) == toupper( (int) c) // oops ?

mais si on transforme d'abord c en unsigned je crois que ouais, ça
correspond à :
std::ctype<char> const& fac std::use_facet<std::ctype<char> >(std::locale("C"))
fac.toupper(c)

--
Sam


Avatar
Michaël Monerau
Samuel Krempp wrote:
le Tuesday 23 September 2003 21:15, écrivit :

Ou dans la dernière édition ;-) que j'ai la chance d'avoir ! Mais
j'en suis quelques 100 pages avant...


argh. moi j'ai la 3°, et je suis très reconnaissant à Bjarne de
fournir ses appendixes.


C'est vrai que c'est une très bonne idée.

En fait, le toupper du C correspondrait à :
// fac == std::use_facet<std::ctype<char> >(std::locale("C"))
fac.toupper (*p1);


si j'ai compris le toupper de string.h,
char c;
toupper(c) == toupper( (int) c) // oops ?

mais si on transforme d'abord c en unsigned je crois que ouais, ça
correspond à :
std::ctype<char> const& fac > std::use_facet<std::ctype<char> >(std::locale("C"))
fac.toupper(c)


Ok. Je verrai ça plus en détail quand j'aurai avancé dans la lecture ;-)
--
<=- Michaël "Cortex" Monerau -=>


Avatar
kanze
Samuel Krempp wrote in message
news:<3f70bbc1$0$2790$...
le Tuesday 23 September 2003 21:15, écrivit :


[...]
Ah oui, d'accord... En fait, ça permet de contourner le problème du
toupper du C...


ben il vaut mieux utiliser les toupper C++ de toutes façon.
effectivement, ils ne posent pas les problèmes de conversion signée
qu'a cette fonction héritée du C.

la plus simple façon d'utiliser std::toupper pour remplacer celui du C
dans <string.h>, c'est std::toupper(*p1, std::locale())


C'est la plus simple, mais ça risque d'être lent -- on va appeler
use_facet pour chaque caractère.

Si on fournit une fonction de comparaison indépendante à la casse,
autant prendre la locale en argument.

(ah là j'ai mis la facet en argument, sans raison particulière)

En fait, le toupper du C correspondrait à :
// fac == std::use_facet<std::ctype<char> >(std::locale("C"))
fac.toupper (*p1);



Pas tout à fait. Le toupper de C dépend également du locale. Le locale
global C établi par setlocale.

Le locale global de C et le locale global de C++ ne sont pas forcement
les même.

si j'ai compris le toupper de string.h,
char c;
toupper(c) == toupper( (int) c) // oops ?

mais si on transforme d'abord c en unsigned


En unsigned char.

je crois que ouais, ça
correspond à :
std::ctype<char> const& fac > std::use_facet<std::ctype<char> >(std::locale("C"))
fac.toupper(c)


Non. Le toupper de C dépend du locale positionné par les appels à
setlocale.

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16