2010-11-27 5 views
14

Comment avez-vous une insertion insensible à la casse Ou la recherche d'une chaîne dans std :: set?Insensible à la casse std :: ensemble de chaînes

Pour exemple-

std::set<std::string> s; 
s.insert("Hello"); 
s.insert("HELLO"); //not allowed, string already exists. 
+1

Pouvez-vous clarifier un peu ce que l'on entend par « cas d'insertion sensible »? – Jon

Répondre

31

Vous devez définir un comparateur personnalisé:

struct InsensitiveCompare { 
    bool operator() (const std::string& a, const std::string& b) const { 
     return stricmp(a.c_str(), b.c_str()) < 0; 
    } 
}; 

std::set<std::string, InsensitiveCompare> s; 
+11

Quand j'ai lu InsensitiveCompare je ne pouvais pas m'empêcher de penser à ma belle-mère. +1 – Fozi

+0

Cette approche ne fonctionnera pas correctement s'il y a des caractères NUL dans une chaîne. Voir [cette question] (https://stackoverflow.com/questions/11635/case-insensitive-string-comparison-in-c). – Sauron

2

std :: set offre la possibilité de fournir votre propre comparateur (comme le font la plupart des conteneurs std). Vous pouvez ensuite effectuer n'importe quel type de comparaison que vous aimez. Exemple complet est disponible here

0

D'après ce que j'ai lu ce qui est plus portable que stricmp() parce stricmp() est en fait pas partie de la bibliothèque std , mais seulement mis en œuvre par la plupart des fournisseurs de compilateurs. Comme résultat ci-dessous est ma solution pour rouler le vôtre.

#include <string> 
#include <cctype> 
#include <iostream> 
#include <set> 

struct caseInsensitiveLess 
{ 
    bool operator()(const std::string& x, const std::string& y) 
    { 
    unsigned int xs (x.size()); 
    unsigned int ys (y.size()); 
    unsigned int bound (0); 

    if (xs < ys) 
     bound = xs; 
    else 
     bound = ys; 

    { 
     unsigned int i = 0; 
     for (auto it1 = x.begin(), it2 = y.begin(); i < bound; ++i, ++it1, ++it2) 
     { 
     if (tolower(*it1) < tolower(*it2)) 
      return true; 

     if (tolower(*it2) < tolower(*it1)) 
      return false; 
     } 
    } 
    return false; 
    } 
}; 

int main() 
{ 
    std::set<std::string, caseInsensitiveLess> ss1; 
    std::set<std::string> ss2; 

    ss1.insert("This is the first string"); 
    ss1.insert("THIS IS THE FIRST STRING"); 
    ss1.insert("THIS IS THE SECOND STRING"); 
    ss1.insert("This IS THE SECOND STRING"); 
    ss1.insert("This IS THE Third"); 

    ss2.insert("this is the first string"); 
    ss2.insert("this is the first string"); 
    ss2.insert("this is the second string"); 
    ss2.insert("this is the second string"); 
    ss2.insert("this is the third"); 

    for (auto& i: ss1) 
    std::cout << i << std::endl; 

    std::cout << std::endl; 

    for (auto& i: ss2) 
    std::cout << i << std::endl; 

} 

sortie avec insensible à la casse et FIXER réguliers montrant la même commande:

This is the first string 
THIS IS THE SECOND STRING 
This IS THE Third 

this is the first string 
this is the second string 
this is the third 
+0

Une petite remarque: si vous travaillez avec, par exemple, Texte grec, cela ne fonctionnera pas car en général il n'est pas possible d'implémenter une comparaison insensible à la casse avec 'tolower' seul. L'exemple de manuel pour cette impossibilité est ΌΣΟΣ qui est insensible à la casse - même chose que όσος (qui est grec pour "autant que"). –