Lorsque j'utilise getline
, je saisis un tas de chaînes ou de nombres, mais je veux que la boucle while génère le "Word" si ce n'est pas un nombre. Existe-t-il un moyen de vérifier si "Word" est un nombre ou non? Je sais que je pourrais utiliser atoi()
pour les chaînes C mais qu'en est-il des chaînes de la classe de chaînes?
int main () {
stringstream ss (stringstream::in | stringstream::out);
string Word;
string str;
getline(cin,str);
ss<<str;
while(ss>>Word)
{
//if( )
cout<<Word<<endl;
}
}
Une autre version...
Utilisez strtol
, en l'enveloppant dans une fonction simple pour masquer sa complexité:
inline bool isInteger(const std::string & s)
{
if(s.empty() || ((!isdigit(s[0])) && (s[0] != '-') && (s[0] != '+'))) return false;
char * p;
strtol(s.c_str(), &p, 10);
return (*p == 0);
}
strtol
?Pour autant que j'aime C++, parfois l'API C est la meilleure réponse en ce qui me concerne:
strtol
semble assez brut à première vue, donc une explication rendra le code plus simple à lire:
strtol
analysera la chaîne, s'arrêtant au premier caractère qui ne peut pas être considéré comme faisant partie d'un entier. Si vous fournissez p
(comme je l'ai fait ci-dessus), il définit p
juste à ce premier caractère non entier.
Mon raisonnement est que si p
n'est pas défini à la fin de la chaîne (le caractère 0), alors il y a un caractère non entier dans la chaîne s
, ce qui signifie s
n'est pas un entier correct.
Les premiers tests sont là pour éliminer les cas d'angle (espaces de tête, chaîne vide, etc.).
Cette fonction doit bien sûr être adaptée à vos besoins (les espaces de début sont-ils une erreur? Etc.).
Voir la description de strtol
sur: http://en.cppreference.com/w/cpp/string/byte/strtol .
Voir aussi la description des fonctions sœurs de strtol
(strtod
, strtoul
, etc.).
La réponse acceptée donnera un faux positif si l'entrée est un nombre plus un texte, car "stol" convertira les premiers chiffres et ignorera le reste.
J'aime le plus la version suivante, car c'est un Nice one-liner qui n'a pas besoin de définir une fonction et vous pouvez simplement copier et coller où vous en avez besoin.
#include <string>
...
std::string s;
bool has_only_digits = (s.find_first_not_of( "0123456789" ) == std::string::npos);
EDIT: si vous aimez cette implémentation mais que vous voulez l'utiliser en tant que fonction, alors cela devrait faire:
bool has_only_digits(const string s){
return s.find_first_not_of( "0123456789" ) == string::npos;
}
Vous pourriez essayer boost::lexical_cast
. Il jette un bad_lexical_cast
exception en cas d'échec.
Dans ton cas:
int number;
try
{
number = boost::lexical_cast<int>(Word);
}
catch(boost::bad_lexical_cast& e)
{
std::cout << Word << "isn't a number" << std::endl;
}
Si vous vérifiez simplement si Word
est un nombre, ce n'est pas trop difficile:
#include <ctype.h>
...
string Word;
bool isNumber = true;
for(string::const_iterator k = Word.begin(); k != Word.end(); ++k)
isNumber &&= isdigit(*k);
Optimisez comme vous le souhaitez.
Utilisez les fonctions C stdio/string toutes puissantes:
int dummy_int;
int scan_value = std::sscanf( some_string.c_str(), "%d", &dummy_int);
if (scan_value == 0)
// does not start with integer
else
// starts with integer
Vous pouvez utiliser boost::lexical_cast
, comme suggéré, mais si vous avez une connaissance préalable des chaînes (c'est-à-dire que si une chaîne contient un littéral entier, elle n'aura pas d'espace de tête, ou que les entiers ne sont jamais écrits avec des exposants), puis rouler votre propre fonction devrait être à la fois plus efficace et pas particulièrement difficile.
Ok, la façon dont je le vois, vous avez 3 options.
1: Si vous souhaitez simplement vérifier si le nombre est un entier, et ne vous souciez pas de le convertir, mais souhaitez simplement le conserver sous forme de chaîne et ne vous souciez pas des débordements potentiels, vérifier s'il correspond à une expression régulière pour un entier serait idéal ici.
2: Vous pouvez utiliser boost :: lexical_cast puis intercepter une exception boost :: bad_lexical_cast potentielle pour voir si la conversion a échoué. Cela fonctionnerait bien si vous pouvez utiliser le boost et si l'échec de la conversion est une condition exceptionnelle.
3: Lancez votre propre fonction similaire à lexical_cast qui vérifie la conversion et retourne vrai/faux selon qu'elle réussit ou non. Cela fonctionnerait dans le cas où 1 & 2 ne correspond pas à vos besoins.
J'ai modifié méthode de paercebal pour répondre à mes besoins:
typedef std::string String;
bool isInt(const String& s, int base){
if(s.empty() || std::isspace(s[0])) return false ;
char * p ;
strtol(s.c_str(), &p, base) ;
return (*p == 0) ;
}
bool isPositiveInt(const String& s, int base){
if(s.empty() || std::isspace(s[0]) || s[0]=='-') return false ;
char * p ;
strtol(s.c_str(), &p, base) ;
return (*p == 0) ;
}
bool isNegativeInt(const String& s, int base){
if(s.empty() || std::isspace(s[0]) || s[0]!='-') return false ;
char * p ;
strtol(s.c_str(), &p, base) ;
return (*p == 0) ;
}
Remarque:
1
, valeur négative ou valeur >36
comme base.0
comme base, il détectera automatiquement la base, c'est-à-dire pour une chaîne commençant par 0x
sera traité comme un hex et une chaîne commençant par 0
sera traité comme oct. Les caractères ne respectent pas la casse.Voici une autre solution.
try
{
(void) std::stoi(myString); //cast to void to ignore the return value
//Success! myString contained an integer
}
catch (const std::logic_error &e)
{
//Failure! myString did not contain an integer
}
template <typename T>
const T to(const string& sval)
{
T val;
stringstream ss;
ss << sval;
ss >> val;
if(ss.fail())
throw runtime_error((string)typeid(T).name() + " type wanted: " + sval);
return val;
}
Et puis vous pouvez l'utiliser comme ça:
double d = to<double>("4.3");
ou
int i = to<int>("4123");