Ou inversement, recherchez le premier caractère non numérique.
Les mêmes fonctions s'appliquent-elles à la chaîne et au caractère *?
Bien sûr, il existe de nombreuses façons de tester une chaîne uniquement pour les caractères numériques. Deux méthodes possibles sont:
bool is_digits(const std::string &str)
{
return str.find_first_not_of("0123456789") == std::string::npos;
}
ou
bool is_digits(const std::string &str)
{
return std::all_of(str.begin(), str.end(), ::isdigit); // C++11
}
Plusieurs personnes ont déjà mentionné d'utiliser isdigit()
. Cependant, notez que ce n'est pas tout à fait trivial car char
peut être signé, ce qui entraînerait la transmission d'une valeur négative à isdigit()
. Cependant, cette fonction ne peut prendre que des valeurs positives. Autrement dit, vous voulez quelque chose qui ressemble à ceci:
if (s.end() == std::find_if(s.begin(), s.end(),
[](unsigned char c)->bool { return !isdigit(c); })) {
std::cout << "string '" << s << "' contains only digits\n";
}
Il semble que le raisonnement pour la conversion en unsigned char
n'est pas évident. Voici donc les citations pertinentes de leurs normes respectives:
Selon ISO/IEC 9899: 2011 (ou ISO/IEC 9899: 1999) 7.4 paragraphe 1, ce qui suit s'applique aux arguments des fonctions de <ctype.h>
:
... Dans tous les cas, l'argument est un
int
, dont la valeur doit être représentable comme ununsigned char
ou doit être égale à la valeur de la macroEOF
. Si l'argument a une autre valeur, le comportement n'est pas défini.
Malheureusement, la norme C++ ne spécifie pas que char
est un type non signé. Au lieu de cela, il spécifie dans ISO/IEC 14882: 2011 3.9.1 [basic.fundamental] paragraphe 1:
... Il est défini par l'implémentation si un objet
char
peut contenir des valeurs négatives. ...
De toute évidence, une valeur négative ne peut pas être représentée par un unsigned char
. Autrement dit, si char
utilise un type signé sur une implémentation (il y en a plusieurs en fait, par exemple, il est signé sur MacOS en utilisant gcc ou clang) il y a le danger que d'appeler l'un des <ctype.h>
la fonction entraînerait un comportement indéfini.
Maintenant, pourquoi la conversion en unsigned char
fait les bonnes choses?
Selon 4.7 [conv.intégratif] paragraphe 2:
Si le type de destination n'est pas signé, la valeur résultante est le moins entier non signé congruent à l'entier source (modulo 2n où n est le nombre de bits utilisés pour représenter le type non signé). [Remarque: dans une représentation du complément à deux, cette conversion est conceptuelle et il n'y a aucun changement dans la configuration binaire (s'il n'y a pas de troncature). —Fin note]
Autrement dit, la conversion d'un char
[potentiellement] signé en unsigned char
est bien défini et fait que le résultat se trouve dans la plage autorisée pour le <ctype.h>
les fonctions.
isdigit(int)
vous indique si un caractère est un chiffre. Si vous allez supposer ASCII et base 10, vous pouvez également utiliser:
int first_non_digit_offset= strspn(string, "0123456789")
Dans le même esprit que la réponse de Misha, mais plus correct: sscanf(buf, "%*u%*c")==1
.
scanf
renvoie 0 si le %d
l'extraction des chiffres échoue, et 2 s'il y a quelque chose après les chiffres capturés par %c
. Et depuis *
empêche la valeur d'être stockée, vous ne pouvez même pas obtenir un débordement.
Le fichier d'en-tête cctype
possède un bon nombre de fonctions de classification de caractères que vous pouvez utiliser sur chaque caractère de la chaîne. Pour les vérifications numériques, ce serait isdigit
.
Le programme suivant montre comment vérifier chaque caractère d'une chaîne C ou C++ (le processus est à peu près identique en termes de vérification des caractères réels, la seule vraie différence étant de savoir comment obtenir la longueur):
#include <iostream>
#include <cstring>
#include <cctype>
int main (void) {
const char *xyzzy = "42x";
std::cout << xyzzy << '\n';
for (int i = 0; i < std::strlen (xyzzy); i++) {
if (! std::isdigit (xyzzy[i])) {
std::cout << xyzzy[i] << " is not numeric.\n";
}
}
std::string plugh ("3141y59");
std::cout << plugh << '\n';
for (int i = 0; i < plugh.length(); i++) {
if (! std::isdigit (plugh[i])) {
std::cout << plugh[i] << " is not numeric.\n";
}
}
return 0;
}
Depuis cplusplus.com vous pouvez utiliser la fonction isdigit comme suit:
// isdigit example (C++)
#include <iostream> // std::cout
#include <string> // std::string
#include <locale> // std::locale, std::isdigit
#include <sstream> // std::stringstream
int main ()
{
std::locale loc;
std::string str="1776ad";
if (isdigit(str[0],loc))
{
int year;
std::stringstream(str) >> year;
std::cout << "The year that followed " << year << " was " << (year+1) << ".\n";
}
return 0;
}
Remarque: il existe 2 types d'isdigit, l'autre version est locale indépendante et basée sur ASCII.
#include <regex>
std::string string( "I only have 3 dollars!" );
std::cout << std::regex_search( string, std::regex( "\\d+" ) ); // true
et
std::string string( "I only have three dollars!" );
std::cout << std::regex_search( string, std::regex( "\\d+" ) ); // false
Si c'est une exigence stricte que vous puissiez trouver exactement où se trouve le premier chiffre sans caractère, vous devrez vérifier chaque caractère. Sinon, j'utiliserais soit quelque chose comme ceci:
unsigned safe_atoi(const std::string& a)
{
std::stringstream s(a);
unsigned b;
s >> b;
return b;
}