Quelle est la meilleure façon de faire une comparaison de chaînes insensible à la casse en C ++ sans transformer une chaîne en majuscules ou en minuscules?
Veuillez indiquer si les méthodes sont compatibles avec Unicode et à quel point elles sont portables.
std::stricmp
. Sinon, lisez ce que Herb a à dire .strcasecmp
ne fait pas partie de la norme et qui manque dans au moins un compilateur commun.Réponses:
Boost comprend un algorithme pratique pour cela:
la source
Profitez de la norme
char_traits
. Rappelons qu'unstd::string
est en fait un typedef pourstd::basic_string<char>
, ou plus explicitement,std::basic_string<char, std::char_traits<char> >
. Lechar_traits
genre décrit comment les personnages se comparent, comment ils copient, comment ils jettent etc. Tout ce que vous devez faire est typedef une nouvelle chaîne surbasic_string
, et de fournir avec votre propre coutumechar_traits
qui comparent insensible à la casse.Les détails sont sur le gourou de la semaine numéro 29 .
la source
typedef std::basic_string<char, ci_char_traits<char> > istring
nontypedef std::basic_string<char, std::char_traits<char> > string
.Le problème avec le boost est que vous devez vous relier au boost et en dépendre. Pas facile dans certains cas (par exemple Android).
Et l'utilisation de char_traits signifie que toutes vos comparaisons sont insensibles à la casse, ce qui n'est généralement pas ce que vous voulez.
Cela devrait suffire. Il devrait être raisonnablement efficace. Ne gère pas unicode ou quoi que ce soit.
Mise à jour: Version Bonus C ++ 14 (
#include <algorithm>
):la source
Si vous êtes sur un système POSIX, vous pouvez utiliser strcasecmp . Cette fonction ne fait pas partie de la norme C, cependant, elle n'est pas non plus disponible sur Windows. Cela effectuera une comparaison insensible à la casse sur les caractères 8 bits, tant que les paramètres régionaux sont POSIX. Si les paramètres régionaux ne sont pas POSIX, les résultats ne sont pas définis (il peut donc effectuer une comparaison localisée ou non). Un équivalent à caractères larges n'est pas disponible.
A défaut, un grand nombre d'implémentations de bibliothèque C historiques ont les fonctions stricmp () et strnicmp (). Visual C ++ sur Windows a renommé tous ces éléments en les préfixant avec un trait de soulignement car ils ne font pas partie de la norme ANSI, donc sur ce système, ils sont appelés _stricmp ou _strnicmp . Certaines bibliothèques peuvent également avoir des fonctions équivalentes à caractères larges ou à plusieurs octets (généralement nommées par exemple wcsicmp, mbcsicmp, etc.).
C et C ++ sont tous deux largement ignorants des problèmes d'internationalisation, il n'y a donc pas de bonne solution à ce problème, sauf pour utiliser une bibliothèque tierce. Consultez IBM ICU (International Components for Unicode) si vous avez besoin d'une bibliothèque robuste pour C / C ++. ICU est destiné aux systèmes Windows et Unix.
la source
Parlez-vous d'une comparaison insensible à la casse ou d'une comparaison Unicode normalisée complète?
Une comparaison stupide ne trouvera pas de chaînes qui pourraient être identiques mais qui ne sont pas égales en binaire.
Exemple:
Sont tous équivalents mais ont également des représentations binaires différentes.
Cela dit, la normalisation Unicode devrait être une lecture obligatoire, surtout si vous prévoyez de prendre en charge le Hangul, le Thaï et d'autres langues asiatiques.
De plus, IBM a à peu près breveté les algorithmes Unicode les plus optimisés et les a rendus publics. Ils maintiennent également une implémentation: IBM ICU
la source
boost :: iequals n'est pas compatible utf-8 dans le cas d'une chaîne. Vous pouvez utiliser boost :: locale .
la source
Ma première pensée pour une version non-unicode a été de faire quelque chose comme ceci:
la source
Vous pouvez utiliser
strcasecmp
sur Unix oustricmp
sur Windows.Une chose qui n'a pas été mentionnée jusqu'à présent est que si vous utilisez des chaînes stl avec ces méthodes, il est utile de comparer d'abord la longueur des deux chaînes, car ces informations sont déjà disponibles dans la classe de chaînes. Cela pourrait empêcher de faire la comparaison de chaînes coûteuse si les deux chaînes que vous comparez ne sont même pas de la même longueur en premier lieu.
la source
Fonctions de chaîne Visual C ++ prenant en charge unicode: http://msdn.microsoft.com/en-us/library/cc194799.aspx
celui que vous cherchez probablement est
_wcsnicmp
la source
J'essaie de concocter une bonne réponse de tous les messages, alors aidez-moi à modifier ceci:
Voici une méthode pour le faire, même si elle transforme les chaînes et n'est pas compatible avec Unicode, elle devrait être portable, ce qui est un avantage:
D'après ce que j'ai lu, c'est plus portable que stricmp () car stricmp () ne fait en fait pas partie de la bibliothèque std, mais seulement implémenté par la plupart des éditeurs de compilateurs.
Pour obtenir une implémentation vraiment Unicode, il semble que vous devez sortir de la bibliothèque std. Une bonne bibliothèque tierce est l' IBM ICU (International Components for Unicode)
Aussi boost :: iequals fournit un assez bon utilitaire pour faire ce genre de comparaison.
la source
transform
la chaîne entière avant la comparaisonVous pouvez utiliser le code ci-dessus en C ++ 14 si vous n'êtes pas en mesure d'utiliser boost. Vous devez utiliser
std::towlower
pour les caractères larges.la source
str1.size() == str2.size() &&
à l'avant afin que cela ne sorte pas des limites lorsque str2 est un préfixe de str1.La bibliothèque Boost.String possède de nombreux algorithmes pour effectuer des comparaisons insensibles à la casse, etc.
Vous pouvez implémenter le vôtre, mais pourquoi s'embêter quand c'est déjà fait?
la source
Pour info,
strcmp()
etstricmp()
sont vulnérables au débordement de tampon, car ils ne traitent que jusqu'à ce qu'ils atteignent un terminateur nul. Il est plus sûr d'utiliser_strncmp()
et_strnicmp()
.la source
stricmp()
etstrnicmp()
ne font pas partie de la norme POSIX :-( Cependant , vous pouvez trouverstrcasecmp()
,strcasecmp_l()
,strncasecmp()
etstrncasecmp_l()
l' en - tête Posixstrings.h
:-) voir opengroup.orgVoir
std::lexicographical_compare
:Démo
la source
std::tolower
ne fonctionne que si le caractère est codé en ASCII. Il n'y a pas de telle garantie pourstd::string
- il peut donc s'agir facilement d'un comportement indéfini.Pour mes besoins de comparaison de chaînes insensibles à la casse, je préfère ne pas avoir à utiliser une bibliothèque externe, ni une classe de chaîne distincte avec des traits insensibles à la casse qui est incompatible avec toutes mes autres chaînes.
Donc, ce que j'ai trouvé, c'est ceci:
Une fonction simple avec une surcharge pour char et une autre pour whar_t. N'utilise rien de non standard, donc ça devrait aller sur n'importe quelle plateforme.
La comparaison d'égalité ne prendra pas en compte les problèmes tels que l'encodage de longueur variable et la normalisation Unicode, mais basic_string n'a aucun support pour cela que je sache de toute façon et ce n'est normalement pas un problème.
Dans les cas où une manipulation lexicographique plus sophistiquée du texte est requise, il vous suffit d'utiliser une bibliothèque tierce comme Boost, ce qui est normal.
la source
Court et agréable. Pas d'autres dépendances, que la bibliothèque std C standard étendue .
renvoie vrai si
str1
etstr2
sont égaux.strcasecmp
peut ne pas exister, il pourrait y avoir des analoguesstricmp
,strcmpi
etc.Exemple de code:
Production:
la source
stricmp
,strcmpi
,strcasecmp
, Etc. Je vous remercie. message modifié.cout << boolalpha
plutôt que mybool2str
car It pour convertir implicitement bool en chars pour stream.Faire cela sans utiliser Boost peut être fait en obtenant le pointeur de chaîne C avec
c_str()
et en utilisantstrcasecmp
:la source
En supposant que vous recherchez une méthode et non une fonction magique qui existe déjà, il n'y a franchement pas de meilleur moyen. Nous pourrions tous écrire des extraits de code avec des astuces intelligentes pour des jeux de caractères limités, mais à la fin de la journée, à un moment donné, vous devez convertir les caractères.
La meilleure approche pour cette conversion est de le faire avant la comparaison. Cela vous permet une grande flexibilité en ce qui concerne les schémas de codage, ce que votre opérateur de comparaison réel devrait ignorer.
Vous pouvez bien sûr «masquer» cette conversion derrière votre propre fonction ou classe de chaîne, mais vous devez toujours convertir les chaînes avant la comparaison.
la source
J'ai écrit une version insensible à la casse de char_traits à utiliser avec std :: basic_string afin de générer une chaîne std :: qui ne respecte pas la casse lors des comparaisons, des recherches, etc. à l'aide des fonctions membres std :: basic_string intégrées.
En d'autres termes, je voulais faire quelque chose comme ça.
... que std :: string ne peut pas gérer. Voici l'utilisation de mes nouveaux char_traits:
... et voici l'implémentation:
la source
J'ai une bonne expérience de l'utilisation du bibliothèques International Components for Unicode - elles sont extrêmement puissantes et fournissent des méthodes pour la conversion, la prise en charge des paramètres régionaux, le rendu de la date et de l'heure, le mappage de casse (que vous ne semblez pas vouloir) et le classement , qui inclut la comparaison insensible à la casse et à l'accent (et plus). Je n'ai utilisé que la version C ++ des bibliothèques, mais elles semblent également avoir une version Java.
Il existe des méthodes pour effectuer des comparaisons normalisées auxquelles fait référence @Coincoin, et peuvent même prendre en compte les paramètres régionaux - par exemple (et ceci est un exemple de tri, pas strictement égal), traditionnellement en espagnol (en Espagne), la combinaison de lettres "ll" trie entre "l" et "m", donc "lz" <"ll" <"ma".
la source
Utilisez-le simplement
strcmp()
pour la comparaison sensible à la casse et /strcmpi()
oustricmp()
pour la casse. Qui sont tous les deux dans le fichier d'en-tête<string.h>
format:
Usage:
Production
apple et ApPlE sont les mêmes
a vient avant b, donc la pomme vient avant la balle
la source
Tard dans la soirée, mais voici une variante qui utilise
std::locale
, et gère donc correctement le turc:vous donne un foncteur qui utilise les paramètres régionaux actifs pour convertir les caractères en minuscules, que vous pouvez ensuite utiliser via
std::transform
pour générer des chaînes en minuscules:Cela fonctionne également pour les
wchar_t
chaînes basées.la source
Juste une note sur la méthode que vous choisissez finalement, si cette méthode inclut l'utilisation de
strcmp
cela, certaines réponses suggèrent:strcmp
ne fonctionne pas avec les données Unicode en général. En général, cela ne fonctionne même pas avec les encodages Unicode basés sur les octets, tels que utf-8, carstrcmp
seules les comparaisons octet par octet et les points de code Unicode encodés dans utf-8 peuvent prendre plus d'un octet. Le seul cas Unicode spécifiquestrcmp
à gérer correctement est lorsqu'une chaîne codée avec un codage basé sur octets ne contient que des points de code inférieurs à U + 00FF - alors la comparaison octet par octet est suffisante.la source
Début 2013, le projet ICU, maintenu par IBM, est une assez bonne réponse à cela.
http://site.icu-project.org/
ICU est une «bibliothèque Unicode complète et portable qui suit de près les normes de l'industrie». Pour le problème spécifique de la comparaison de chaînes, l'objet Collation fait ce que vous voulez.
Le projet Mozilla a adopté ICU pour l'internationalisation dans Firefox à la mi-2012; vous pouvez suivre la discussion d'ingénierie, y compris les problèmes de génération de systèmes et de taille de fichier de données, ici:
la source
Il semble que les solutions ci-dessus n'utilisent pas la méthode de comparaison et n'implémentent à nouveau le total, alors voici ma solution et j'espère que cela fonctionne pour vous (cela fonctionne bien).
la source
Si vous ne voulez pas utiliser la bibliothèque Boost, voici la solution en utilisant uniquement l'en-tête io standard C ++.
la source
Si vous devez comparer une chaîne source plus souvent avec d'autres chaînes, une solution élégante consiste à utiliser l'expression régulière.
la source
error: conversion from 'const char [5]' to non-scalar type 'std::wstring {aka std::basic_string<wchar_t>}' requested
Un moyen simple de comparer deux chaînes en c ++ (testé pour Windows) utilise _stricmp
Si vous cherchez à utiliser avec std :: string, un exemple:
Pour plus d'informations ici: https://msdn.microsoft.com/it-it/library/e0z9k731.aspx
la source
cela pourrait probablement être rendu beaucoup plus efficace, mais voici une version volumineuse avec tous ses bits à nu.
pas tout à fait portable, mais fonctionne bien avec tout ce qui est sur mon ordinateur (aucune idée, je suis des images pas des mots)
la source
Un moyen simple de comparer des chaînes qui ne diffèrent que par des minuscules et des majuscules consiste à effectuer une comparaison ascii. Toutes les lettres majuscules et minuscules diffèrent de 32 bits dans le tableau ascii, en utilisant ces informations, nous avons ce qui suit ...
la source