web-dev-qa-db-fra.com

comment vérifier si une chaîne ou un caractère c ++ donné ne contient que des chiffres?

Ou inversement, recherchez le premier caractère non numérique.

Les mêmes fonctions s'appliquent-elles à la chaîne et au caractère *?

45
rsk82

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
}
96
Blastfurnace

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 un unsigned char ou doit être égale à la valeur de la macro EOF. 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.

12
Dietmar Kühl

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")
5
MSN

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.

4
MSalters

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;
}
3
paxdiablo

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.

1
newComer

#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
0
Shakiba Moshiri

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;
}
0
Yuushi