Comment convertir un nombre en chaîne et vice versa en C ++

120

Étant donné que cette question est posée chaque semaine, cette FAQ pourrait aider de nombreux utilisateurs.

  • Comment convertir un entier en chaîne en C ++

  • comment convertir une chaîne en un entier en C ++

  • comment convertir un nombre à virgule flottante en une chaîne en C ++

  • comment convertir une chaîne en nombre à virgule flottante en C ++

Armen Tsirunyan
la source
Pour une conversion comme celle-ci, j'ai un signet converttypes.com
Firzok Nadeem

Réponses:

129

Mise à jour pour C ++ 11

À partir de la C++11norme, la conversion chaîne en nombre et vice-versa est intégrée à la bibliothèque standard. Toutes les fonctions suivantes sont présentes dans <string>(conformément au paragraphe 21.5).

chaîne en numérique

float              stof(const string& str, size_t *idx = 0);
double             stod(const string& str, size_t *idx = 0);
long double        stold(const string& str, size_t *idx = 0);
int                stoi(const string& str, size_t *idx = 0, int base = 10);
long               stol(const string& str, size_t *idx = 0, int base = 10);
unsigned long      stoul(const string& str, size_t *idx = 0, int base = 10);
long long          stoll(const string& str, size_t *idx = 0, int base = 10);
unsigned long long stoull(const string& str, size_t *idx = 0, int base = 10);

Chacun de ceux-ci prend une chaîne en entrée et essaiera de la convertir en nombre. Si aucun nombre valide n'a pu être construit, par exemple parce qu'il n'y a pas de données numériques ou parce que le nombre est hors limites pour le type, une exception est levée ( std::invalid_argumentou std::out_of_range).

Si la conversion a réussi et idxne l'est pas 0,idx contiendra l'index du premier caractère qui n'a pas été utilisé pour le décodage. Cela peut être un index derrière le dernier caractère.

Enfin, les types intégraux permettent de spécifier une base, pour les chiffres supérieurs à 9, l'alphabet est supposé ( a=10jusqu'à z=35). Vous pouvez trouver plus d'informations sur la mise en forme exacte qui peut être analysée ici pour les nombres à virgule flottante , les entiers signés et les entiers non signés .

Enfin, pour chaque fonction, il existe également une surcharge qui accepte un std::wstringcomme premier paramètre.

numérique en chaîne

string to_string(int val);
string to_string(unsigned val);
string to_string(long val);
string to_string(unsigned long val);
string to_string(long long val);
string to_string(unsigned long long val);
string to_string(float val);
string to_string(double val);
string to_string(long double val);

Ceux-ci sont plus simples, vous passez le type numérique approprié et vous récupérez une chaîne. Pour les options de formatage, vous devez revenir à l'option stringsream C ++ 03 et utiliser des manipulateurs de flux, comme expliqué dans une autre réponse ici.

Comme indiqué dans les commentaires, ces fonctions reviennent à une précision de mantisse par défaut qui n'est probablement pas la précision maximale. Si plus de précision est requise pour votre application, il est également préférable de revenir à d'autres procédures de formatage de chaîne.

Il existe également des fonctions similaires définies qui sont nommées to_wstring, elles renverront un fichier std::wstring.

KillianDS
la source
3
std::to_stringperd beaucoup de précision pour les types à virgule flottante. Par exemple, double f = 23.4323897462387526; std::string f_str = std::to_string(f);renvoie une chaîne de 23,432390. Cela rend impossible d'aller-retour des valeurs en virgule flottante en utilisant ces fonctions.
fun4jimmy
@ fun4jimmy est-ce une restriction imposée par le standard ou une implémentation spécifique? L'ajoutera à la réponse. Ce n'est pas que le fait d'aller-retour flotte à travers les cordes soit une bonne idée.
KillianDS
Le standard C ++ dit " Renvoie: Chaque fonction renvoie un objet chaîne contenant la représentation en caractères de la valeur de son argument qui serait générée en appelant sprintf(buf, fmt, val)avec un spécificateur de format de "% d " , "% u " , "% ld " , " % lu " , "% lld " , "% llu " , "% f " , "% f " ou "% Lf " , respectivement, où bufdésigne un tampon de caractères interne de taille suffisante. " J'ai jeté un coup d'œil au C99 standard pour printf et je pense que le nombre de décimales dépend #define DECIMAL_DIGdefloat.h .
fun4jimmy
Bruce Dawson a quelques bons articles sur la précision nécessaire pour les nombres à virgule flottante à déclenchement circulaire sur son blog .
fun4jimmy
2
Toutes ces fonctions sont affectées par les paramètres régionaux globaux, ce qui peut entraîner des problèmes si vous utilisez des bibliothèques, et en particulier si vous utilisez des threads. Voir ma question ici: stackoverflow.com/questions/31977457/…
Ident
87

Comment convertir un nombre en chaîne en C ++ 03

  1. N'utilisez pas lesfonctionsitoaouitofcar elles ne sont pas standard et donc non portables.
  2. Utiliser des flux de chaînes

     #include <sstream>  //include this to use string streams
     #include <string> 
    
    int main()
    {    
        int number = 1234;
    
        std::ostringstream ostr; //output string stream
        ostr << number; //use the string stream just like cout,
        //except the stream prints not to stdout but to a string.
    
        std::string theNumberString = ostr.str(); //the str() function of the stream 
        //returns the string.
    
        //now  theNumberString is "1234"  
    }

    Notez que vous pouvez également utiliser des flux de chaînes pour convertir des nombres à virgule flottante en chaîne, et également pour formater la chaîne comme vous le souhaitez, comme avec cout

    std::ostringstream ostr;
    float f = 1.2;
    int i = 3;
    ostr << f << " + " i << " = " << f + i;   
    std::string s = ostr.str();
    //now s is "1.2 + 3 = 4.2" 

    Vous pouvez utiliser des manipulateurs de flux, tels que std::endl, std::hexet des fonctions std::setw(), std::setprecision()etc. avec des flux de chaînes exactement de la même manière qu'aveccout

    Ne confondez pas std::ostringstream avecstd::ostrstream. Ce dernier est obsolète

  3. Utilisez la distribution lexicale boost . Si vous n'êtes pas familier avec boost, c'est une bonne idée de commencer avec une petite bibliothèque comme celle-ci lexical_cast. Pour télécharger et installer boost et sa documentation, allez ici . Bien que boost ne soit pas dans la norme C ++, de nombreuses bibliothèques de boost sont finalement standardisées et boost est largement considéré comme les meilleures bibliothèques C ++.

    La distribution lexicale utilise des flux en dessous, donc fondamentalement cette option est la même que la précédente, juste moins verbeuse.

    #include <boost/lexical_cast.hpp>
    #include <string>
    
    int main()
    {
       float f = 1.2;
       int i = 42;
       std::string sf = boost::lexical_cast<std::string>(f); //sf is "1.2"
       std::string si = boost::lexical_cast<std::string>(i); //sf is "42"
    }

Comment convertir une chaîne en nombre en C ++ 03

  1. L'option la plus légère, héritée de C, est les fonctions atoi(pour les entiers (alphabétique à entier)) et atof(pour les valeurs à virgule flottante (alphabétique à float)). Ces fonctions prennent une chaîne de style C comme argument ( const char *) et par conséquent, leur utilisation peut être considérée comme une mauvaise pratique C ++. cplusplus.com a une documentation facile à comprendre sur atoi et atof, y compris comment ils se comportent en cas de mauvaise saisie. Cependant, le lien contient une erreur en ce que selon la norme si le nombre d'entrée est trop grand pour tenir dans le type de cible, le comportement est indéfini.

    #include <cstdlib> //the standard C library header
    #include <string>
    int main()
    {
        std::string si = "12";
        std::string sf = "1.2";
        int i = atoi(si.c_str()); //the c_str() function "converts" 
        double f = atof(sf.c_str()); //std::string to const char*
    }
  2. Utilisez des flux de chaînes (cette fois, des flux de chaînes d'entrée istringstream). Encore une fois, istringstream est utilisé comme cin. Encore une fois, ne confondez pas istringstreamavec istrstream. Ce dernier est obsolète.

    #include <sstream>
    #include <string>
    int main()
    {
       std::string inputString = "1234 12.3 44";
       std::istringstream istr(inputString);
       int i1, i2;
       float f;
       istr >> i1 >> f >> i2;
       //i1 is 1234, f is 12.3, i2 is 44  
    }
  3. Utilisez la distribution lexicale boost .

    #include <boost/lexical_cast.hpp>
    #include <string>
    
    int main()
    {
       std::string sf = "42.2"; 
       std::string si = "42";
       float f = boost::lexical_cast<float>(sf); //f is 42.2
       int i = boost::lexical_cast<int>(si);  //i is 42
    }       

    En cas de mauvaise entrée, lexical_castlance une exception de typeboost::bad_lexical_cast

Armen Tsirunyan
la source
4
La documentation de cplusplus pour atoin'est pas excellente, elle est incorrecte. Il ne mentionne pas que si la valeur numérique de la chaîne ne peut pas être représentée dans int, alors le comportement n'est pas défini. Il dit à la place que les valeurs hors limites sont fixées à INT_MAX/ INT_MIN, ce que je ne trouve ni dans C ++ 03 ni dans C89. Pour les entrées non approuvées / non vérifiées, ou lors de l'utilisation de bases que les flux ne prennent pas en charge, vous avez besoin de strtolce qui a défini le comportement d'erreur. Et des commentaires similaires pour atof/ strtod.
Steve Jessop
2
cplusplus.com se trompe sur "atoi". Il dit à propos de la valeur de retour "Si aucune conversion valide n'a pu être effectuée, une valeur zéro est renvoyée. Si la valeur correcte est en dehors de la plage des valeurs représentables, INT_MAX ou INT_MIN est retourné.", Mais la spécification dit que "Si le la valeur du résultat ne peut pas être représentée, le comportement n'est pas défini. " et que "Sauf pour le comportement en cas d'erreur, ils sont équivalents à (int)strtol(nptr, (char **)NULL, 10). Les fonctions atoi [...] renvoient la valeur convertie.". cplusplus.com est connu pour être une incroyable mauvaise source d'informations pour les débutants.
Johannes Schaub - litb
istr >> i1 >> f >> i2;rate gravement un test de succès.
sbi
4
std::to_string
Pourrait
1
@ArmenTsirunyan: +10 de ma fin, une des meilleures réponses que j'aie jamais vues aussi en profondeur. Merci pour votre réponse.
Abhineet le
4

En C ++ 17, les nouvelles fonctions std :: to_chars et std :: from_chars sont introduites dans l'en-tête charconv .

std :: to_chars est indépendant des paramètres régionaux, sans allocation et sans lancement.

Seul un petit sous-ensemble de politiques de formatage utilisées par d'autres bibliothèques (telles que std :: sprintf) est fourni.

De std :: to_chars , même chose pour std :: from_chars .

La garantie que std :: from_chars peut récupérer chaque valeur à virgule flottante formatée par to_chars exactement n'est fournie que si les deux fonctions proviennent de la même implémentation

 // See en.cppreference.com for more information, including format control.
#include <cstdio>
#include <cstddef>
#include <cstdlib>
#include <cassert>
#include <charconv>

using Type =  /* Any fundamental type */ ;
std::size_t buffer_size = /* ... */ ;

[[noreturn]] void report_and_exit(int ret, const char *output) noexcept 
{
    std::printf("%s\n", output);
    std::exit(ret);
}
void check(const std::errc &ec) noexcept
{
    if (ec ==  std::errc::value_too_large)
        report_and_exit(1, "Failed");
}
int main() {
    char buffer[buffer_size];        
    Type val_to_be_converted, result_of_converted_back;

    auto result1 = std::to_chars(buffer, buffer + buffer_size,  val_to_be_converted);
    check(result1.ec);
    *result1.ptr = '\0';

    auto result2 = std::from_chars(buffer, result1.ptr, result_of_converted_back);
    check(result2.ec);

    assert(val_to_be_converted == result_of_converted_back);
    report_and_exit(0, buffer);
}

Bien qu'il ne soit pas entièrement implémenté par les compilateurs, il le sera certainement.

JiaHao Xu
la source
0

J'ai volé cette classe pratique quelque part ici à StackOverflow pour convertir tout ce qui peut être diffusé en chaîne:

// make_string
class make_string {
public:
  template <typename T>
  make_string& operator<<( T const & val ) {
    buffer_ << val;
    return *this;
  }
  operator std::string() const {
    return buffer_.str();
  }
private:
  std::ostringstream buffer_;
};

Et puis vous l'utilisez comme;

string str = make_string() << 6 << 8 << "hello";

Assez chouette!

J'utilise également cette fonction pour convertir des chaînes en quelque chose de streamable, mais ce n'est pas très sûr si vous essayez d'analyser une chaîne ne contenant pas de nombre; (et ce n'est pas aussi intelligent que le dernier non plus)

// parse_string
template <typename RETURN_TYPE, typename STRING_TYPE>
RETURN_TYPE parse_string(const STRING_TYPE& str) {
  std::stringstream buf;
  buf << str;
  RETURN_TYPE val;
  buf >> val;
  return val;
}

Utilisé comme:

int x = parse_string<int>("78");

Vous pouvez également vouloir des versions pour wstrings.

Viktor Sehr
la source
5
C'est exactement ce que fait boost :: lexical_cast. Et le boost le fait de manière plus générique.
Armen Tsirunyan
Certes, j'ai parcouru la première réponse et je n'ai pas vu le boost :: lexical_casts.
Viktor Sehr