comparaison de chaine "case-insensitive" en c++

comparaison de chaine "case-insensitive" en c++ - C++ - Programmation

Marsh Posté le 01-02-2003 à 15:25:26    

Je me demande quel le moyen le plus "propre" pour comparer deux std::string sans prendre en compte la casse des caractères ? strcasecmp c'est bien mais c'est pas du c++ et la portabilité est douteuse. Y'a une feinte avec les facets ou un truc du genre ?
 
Je précise que c'est pas pour comparer des chaine des caractères chinois en UTF8, c'est juste pour des chaines en ascii 7 bit donc rien de méchant

Reply

Marsh Posté le 01-02-2003 à 15:25:26   

Reply

Marsh Posté le 01-02-2003 à 15:30:46    

Captain ad-hoc a écrit :

Je me demande quel le moyen le plus "propre" pour comparer deux std::string sans prendre en compte la casse des caractères ? strcasecmp c'est bien mais c'est pas du c++ et la portabilité est douteuse. Y'a une feinte avec les facets ou un truc du genre ?
 
Je précise que c'est pas pour comparer des chaine des caractères chinois en UTF8, c'est juste pour des chaines en ascii 7 bit donc rien de méchant


tu peux faire une boucle explicite pour comparer et utiliser toupper () sur chaque caractere pour la comparaison. dans la classe basic_string, y a pas de fonction pour la comparaison sans tenir compte de la casse

Reply

Marsh Posté le 01-02-2003 à 15:50:12    

Utilises ca avec une fonction de comparaison de char adaptée :
 
http://www.sgi.com/tech/stl/lexico [...] mpare.html


Message édité par Kristoph le 01-02-2003 à 15:51:40
Reply

Marsh Posté le 01-02-2003 à 15:55:05    

Kristoph a écrit :

Utilises ca avec une fonction de comparaison de char adaptée :
 
http://www.sgi.com/tech/stl/lexico [...] mpare.html


j'l'avais oublié celle la  :)  
mais ce qui est un peu chiant c'est qu'elle renvoie un booléen:

  • true lorsque la 1ere séquence est < à la 2è
  • false qd elles sont égales (logique !  :D )

par contre elle est utilisable sur toutes les séquences

Reply

Marsh Posté le 01-02-2003 à 15:59:09    

ouaip, 2 solutions:
- copier les 2chaines a comparer, convertir chaque caractère en minuscule/majuscule avec std::toupper/std::tolower, et comparer avec le std::string::compare ou <, >, etc
 
- réécrire une std::strcmp, avec std::tolower(s1[i]) ?? std::tolower(s2[i]). sans doute la meilleur solution surtout si les chaines sont longues, à condtion de pas coder comme un pied. donc je propose
 
 

Code :
  1. #include <cctype>
  2. #include <string>
  3. int StringCaseCompare(const std::string &s1, const std::string &s2)
  4. {
  5.   int c1, c2;
  6.   const size_t len1(s1.length()), len2(s2.length()), min_len(std::min(len1, len2));
  7.   for(size_t i=0; i<min_len; ++i)
  8.     {
  9.       c1=std::tolower(s1[i]);
  10.       c2=std::tolower(s2[i]);
  11.       if(c1!=c2)
  12. {
  13.   return c1-c2;
  14. }
  15.     }
  16.   return len1-len2;
  17. }


Message édité par Taz le 01-02-2003 à 16:06:56
Reply

Marsh Posté le 01-02-2003 à 16:02:04    

Code :
  1. int cmpNoCase (const std::string &s1, const std::string &s2)
  2. {
  3.    std::string::const_iterator i1 = s1.begin ();
  4.    std::string::const_iterator i2 = s2.begin ();
  5.    while (i1 != s1.end () && i2 != s2.end ())
  6.    {
  7.       if (toupper (*i1) != toupper (*i2))
  8.          return (toupper (*i1) < toupper (*i2)) ? -1 : 1;
  9.       ++i1; ++i2;
  10.    }
  11.    return (s1.size () == s2.size ()) ? 0 : (s1.size () < s2.size () ? -1 : 1);
  12. }

Reply

Marsh Posté le 01-02-2003 à 16:03:07    

ma version est bien plus performante  :na:
 
edit: arg, j'ai oublié de traiter le cas final

Message cité 1 fois
Message édité par Taz le 01-02-2003 à 16:05:40
Reply

Marsh Posté le 01-02-2003 à 16:04:21    

++Taz a écrit :

ma version est bien plus performante  :na:  


mais elle marche mal   :na:

Reply

Marsh Posté le 01-02-2003 à 16:07:41    

gloop a écrit :


mais elle marche mal   :na:  

a y est.
 
il me semble que strcmp renvoie une différence de caractère et pas seulement -1, 0, ou 1...  
 
edit: oups, ça dépend de l'implémentation: en fait c'est valeur <0, ==0 ou >0


Message édité par Taz le 01-02-2003 à 16:11:46
Reply

Marsh Posté le 01-02-2003 à 16:12:55    

gloop a écrit :


mais elle marche mal   :na:  

cela dit merci à toi de montrer par l'exemple que bien que les string soit des pseudo-containers, elles proposent des itérateurs  :jap:

Reply

Marsh Posté le 01-02-2003 à 16:12:55   

Reply

Marsh Posté le 01-02-2003 à 16:13:18    

ok, merci les ptits gars pour vos réponses [:welcom] c'est quand même dommage qu'il n'y ait rien de tout cuit pour ça dans la class basic_string je trouve  :(

Reply

Marsh Posté le 01-02-2003 à 16:21:16    

skom ça...faut dire aussi que la comarasion pas sensible à la casse est tres dure à définir (en francais, les majuscules doivent etre accentuées ou avoir une cédille, personne ne le fait, et pourtant), cela dépend beaucoup du contexte local.

Reply

Marsh Posté le 01-02-2003 à 16:52:27    

Ce cas figure dans un bouquin ("mieux programmer en C++" je crois)
Malheureusement je ne l'ai pas sous les yeux et c'est assez loin :(
Je me souvient qu'ils ont créé leur propre fonction compare de char_traits que string utilise et ont créé leur classe identique a string sauf qu'elle utilise cette fonction de comparaison. Y'avait ensuite une discution sur l'utilité d'une telle classe ... arf c'est un peu loin.
Mais voila de quoi te donner un piste :
la fonction de comparaison utilisee est dans char_traits.h

Code :
  1. // class char_traits<char>
  2. static int compare(const char* __s1, const char* __s2, size_t __n)
  3.     { return memcmp(__s1, __s2, __n); }


faut remplacer par memicmp.
 
string est definie ainsi :

Code :
  1. template <class _CharT,
  2.           class _Traits = char_traits<_CharT>,
  3.           class _Alloc = __STL_DEFAULT_ALLOCATOR(_CharT) >
  4. class basic_string;
  5. typedef basic_string<char>    string;


 
faut modifier le char_traits utilisé, peut etre un truc du genre :

Code :
  1. template <class _CharT,
  2.           class _Traits = ichar_traits<_CharT>,
  3.           class _Alloc = __STL_DEFAULT_ALLOCATOR(_CharT) >
  4. class [b]insensitive_string[b];
  5. typedef insensitive_string<char>    istring;


 
enfin c'est une piste, car les templates, je m'y suis jamais plongé.


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
Reply

Marsh Posté le 01-02-2003 à 16:56:31    

HelloWorld a écrit :

Ce cas figure dans un bouquin ("mieux programmer en C++" je crois)
Malheureusement je ne l'ai pas sous les yeux et c'est assez loin :(
Je me souvient qu'ils ont créé leur propre fonction compare de char_traits que string utilise et ont créé leur classe identique a string sauf qu'elle utilise cette fonction de comparaison. Y'avait ensuite une discution sur l'utilité d'une telle classe ... arf c'est un peu loin.
Mais voila de quoi te donner un piste :
la fonction de comparaison utilisee est dans char_traits.h

Code :
  1. // class char_traits<char>
  2. static int compare(const char* __s1, const char* __s2, size_t __n)
  3.     { return memcmp(__s1, __s2, __n); }


faut remplacer par memicmp.
 
string est definie ainsi :

Code :
  1. template <class _CharT,
  2.           class _Traits = char_traits<_CharT>,
  3.           class _Alloc = __STL_DEFAULT_ALLOCATOR(_CharT) >
  4. class basic_string;
  5. typedef basic_string<char>    string;


 
faut modifier le char_traits utilisé, peut etre un truc du genre :

Code :
  1. template <class _CharT,
  2.           class _Traits = ichar_traits<_CharT>,
  3.           class _Alloc = __STL_DEFAULT_ALLOCATOR(_CharT) >
  4. class [b]insensitive_string[b];
  5. typedef insensitive_string<char>    istring;


 
enfin c'est une piste, car les templates, je m'y suis jamais plongé.


 
c une bonne idée , mais ca oblige à utiliser 2 types pour les chaines de caractéres. et en + si t'as besoin de comparer un string et istring, c pas le + pratique

Reply

Marsh Posté le 02-02-2003 à 01:50:50    

Je crois que c'etait un des points souleves quant a l'utilite de cette classe : que faire lors de la comparaison d'une string avec une istring.
Et sinon, un simple

Code :
  1. bool IsEqual( std::string s1, std::string s2 )
  2. {
  3.     return ( ::stricmp( s1.c_str(), s2.c_str() ) == 0 ),
  4. }


 
Parce que bon, copier les 2 chaines, les convertir en upper, ca me parrait bourrin quand même.


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
Reply

Marsh Posté le 02-02-2003 à 07:19:52    

trucicmp connait po  :na:  
 
avec gloop on s'est employé a trouver la solution standard, sinon j'aurais vite dégainé une page de man. bien joué les liens de HW, c'est une bonne idée de tout enrober dans une classe, mais j'aurais pas été jusqu'au point de créer un nouveau type de string, je me serai contenté de fonctions membres statiques pour usage

Reply

Marsh Posté le 02-02-2003 à 16:16:55    

Je savais pas que c'etait pas standard.
On la trouve quand meme a peu pres partout cette fonction. C'est un standard du non-standard ! :)


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
Reply

Marsh Posté le 02-02-2003 à 16:36:02    

PARTOUT mais pas POSIX  :pfff:

Reply

Marsh Posté le 04-02-2003 à 12:09:34    

Coucou,  
 
Je sais qu'au depart on ne compare que des chaines de caracteres 7bits, mais si on s'interresse au probleme des accents, quelle est la meilleure solution.  
 
Deux cas :  
1- on veut ignorer la casse ET les accents,  
2- on veut ignorer la casse mais respecter les accents,  
 
Perso je vois pas d'autre solution qu'une implementation similaire a celle de ++Taz, ou l'on ferait caractere par caractere et, si le caractere n'est pas ascii (<0) on se tape une recherche dans une table associant chaque caractere special a son equivalent majuscule, avec ou sans accent suivant le cas.  
 
Qu'en pensez vous ?  
 

Reply

Marsh Posté le 16-07-2008 à 11:48:31    

Taz a écrit :

ma version est bien plus performante  :na:
 
edit: arg, j'ai oublié de traiter le cas final


 
 
 
Bonjour Taz,
 
Ton code me plait mais je ne vois pas de quel cas final tu parles?
merci de m'apporter une précision.

Reply

Marsh Posté le 16-07-2008 à 16:41:47    

le_num a écrit :


 
 
 
Bonjour Taz,
 
Ton code me plait mais je ne vois pas de quel cas final tu parles?
merci de m'apporter une précision.


 
il a déjà edité et corrigé, c'est pour ca que ca te plait [:dawa]

Reply

Marsh Posté le 16-07-2008 à 20:53:28    

ya un Gotw à ce propos:
 
http://www.gotw.ca/gotw/029.htm


---------------
You can't start a fire with moonlight
Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed