Comment puis-je convertir une chaîne std :: en int?


485

Juste une petite question. J'ai regardé un peu sur Internet et j'ai trouvé quelques solutions, mais aucune d'entre elles n'a encore fonctionné. Vous cherchez à convertir une chaîne en entier et je ne parle pas de codes ASCII.

Pour une analyse rapide, nous sommes passés dans une équation sous forme de chaîne. Nous devons le décomposer, le formater correctement et résoudre les équations linéaires. Maintenant, en disant cela, je ne suis pas en mesure de convertir une chaîne en entier.

Je sais que la chaîne sera au format (-5) ou (25) etc. donc c'est définitivement un int. Mais comment extraire cela d'une chaîne?

Je pensais notamment à exécuter une boucle for / while dans la chaîne, à rechercher un chiffre, à extraire tous les chiffres après cela, puis à voir s'il y avait un `` - '', s'il y en a un, à multiplier l'int par - 1.

Cela semble un peu trop compliqué pour un si petit problème. Des idées?


9
As-tu essayé atoi()?
i_am_jorf



7
@Chad Vous recommandez donc qu'il utilise une bibliothèque entière pour quelque chose que la langue peut faire avec les bibliothèques standard de toute façon?
Bojangles

6
@Brandon, si vous en avez un std::string myStringet que atoivous voulez l' utiliser , alors vous voulez dire atoi(myString.c_str()).
Robᵩ

Réponses:


727

En C ++ 11, il y a de belles nouvelles fonctions de conversion de std::stringà un type numérique.

Donc au lieu de

atoi( str.c_str() )

vous pouvez utiliser

std::stoi( str )

strest votre numéro std::string.

Il y a version pour toutes les saveurs de chiffres: long stol(string), float stof(string), double stod(string), ... voir http://en.cppreference.com/w/cpp/string/basic_string/stol


5
Pour les problèmes avec std :: stoi, voir stackoverflow.com/a/6154614/195527 : il se convertira "11x"en entier 11.
CC.

5
#include <stdlib.h> / * atoi * /
Ulad Kasach

4
@CC C'est aussi le comportement de atoi: cplusplus.com/reference/cstdlib/atoi "La chaîne peut contenir des caractères supplémentaires après ceux qui forment le nombre entier, qui sont ignorés et n'ont aucun effet sur le comportement de cette fonction."
Tin Wizard

4
Pourriez-vous mettre à jour cette réponse avec from_charsC ++ 17? Il est censé être des ordres de grandeur plus rapides que stoi.
NathanOliver

stoidevrait être préféré. Voir Pourquoi ne devrais-je pas utiliser atoi ()?
phuclv

57
std::istringstream ss(thestring);
ss >> thevalue;

Pour être complètement correct, vous voudrez vérifier les drapeaux d'erreur.


2
Cela ne sera pas extrait -5de (-5).
Nawaz

@Nawaz, les parens sont-ils réellement là, ou est-ce juste ainsi que le PO présente ses cordes?
Winston Ewert

Je ne sais pas. Je souligne simplement les limites de l'approche.
Nawaz

16
@Nawaz, Il ne peut pas non plus fonctionner sur l'entrée "WERWER". Je ne pense pas que les parens fassent réellement partie de sa chaîne et je ne pense pas que le fait de ne pas les analyser soit pertinent.
Winston Ewert

4
@Nawaz, ok ... Je ne prends pas le mot comme ça mais je vois comment tu pourrais.
Winston Ewert

44

Les options possibles sont décrites ci-dessous:

1. Première option: sscanf ()

    #include <cstdio>
    #include <string>

        int i;
        float f;
        double d;
        std::string str;

        // string -> integer
        if(sscanf(str.c_str(), "%d", &i) != 1)
            // error management

        // string -> float
        if(sscanf(str.c_str(), "%f", &f) != 1)
            // error management

        // string -> double 
        if(sscanf(str.c_str(), "%lf", &d) != 1)
            // error management

Il s'agit d'une erreur (également affichée par cppcheck) car "scanf sans limites de largeur de champ peut planter avec d'énormes données d'entrée sur certaines versions de libc" (voir ici et ici ).

2. Deuxième option: std :: sto * ()

    #include <iostream>
    #include <string>

        int i;
        float f;
        double d;
        std::string str;

        try {
            // string -> integer
            int i = std::stoi(str);

            // string -> float
            float f = std::stof(str);

            // string -> double 
            double d = std::stod(str);
        } catch (...) {
            // error management
        }   

Cette solution est courte et élégante, mais elle n'est disponible que sur les compilateurs compatibles C ++ 11.

3. Troisième option: sstreams

    #include <string>
    #include <sstream>

        int i;
        float f;
        double d;
        std::string str;

        // string -> integer
        std::istringstream ( str ) >> i;

        // string -> float
        std::istringstream ( str ) >> f;

        // string -> double 
        std::istringstream ( str ) >> d;

        // error management ??

Cependant, avec cette solution, il est difficile de distinguer les mauvaises entrées (voir ici ).

4. Quatrième option: lexical_cast de Boost

    #include <boost/lexical_cast.hpp>
    #include <string>

        std::string str;

        try {
            int i = boost::lexical_cast<int>( str.c_str());
            float f = boost::lexical_cast<int>( str.c_str());
            double d = boost::lexical_cast<int>( str.c_str());
            } catch( boost::bad_lexical_cast const& ) {
                // Error management
        }

Cependant, ce n'est qu'un wrapper de sstream, et la documentation suggère d'utiliser sstreampour une meilleure gestion des erreurs (voir ici ).

5. Cinquième option: strto * ()

Cette solution est très longue, en raison de la gestion des erreurs, et elle est décrite ici. Comme aucune fonction ne renvoie un entier simple, une conversion est nécessaire en cas d'entier (voir ici comment cette conversion peut être réalisée).

6. Sixième option: Qt

    #include <QString>
    #include <string>

        bool ok;
        std::string;

        int i = QString::fromStdString(str).toInt(&ok);
        if (!ok)
            // Error management

        float f = QString::fromStdString(str).toFloat(&ok);
        if (!ok)
            // Error management 

        double d = QString::fromStdString(str).toDouble(&ok);
        if (!ok)
    // Error management     

Conclusions

En résumé, la meilleure solution est C ++ 11 std::stoi()ou, comme deuxième option, l'utilisation de bibliothèques Qt. Toutes les autres solutions sont déconseillées ou boguées.


Fixé. Merci d'avoir signalé.
Claudio

Beau résumé, merci beaucoup. Puis-je suggérer d'ajouter un premier commentaire suggérant la solution finale afin que seules les personnes intéressées par les détails continuent à lire?
luca

1
cela devrait être la réponse acceptée, vous avez également oublié (ou plutôt devrait ajouter car c'est une ancienne réponse) from_chars
xception


9

Qu'en est-il de Boost.Lexical_cast ?

Voici leur exemple:

L'exemple suivant traite les arguments de ligne de commande comme une séquence de données numériques:

int main(int argc, char * argv[])
{
    using boost::lexical_cast;
    using boost::bad_lexical_cast;

    std::vector<short> args;

    while(*++argv)
    {
        try
        {
            args.push_back(lexical_cast<short>(*argv));
        }
        catch(bad_lexical_cast &)
        {
            args.push_back(0);
        }
    }
    ...
}

Le lien est rompu. Pourriez-vous le réparer?
Yuchen Zhong

5

Certes, ma solution ne fonctionnerait pas pour les entiers négatifs, mais elle extraira tous les entiers positifs du texte d'entrée contenant des entiers. Il utilise les numeric_onlyparamètres régionaux:

int main() {
        int num;
        std::cin.imbue(std::locale(std::locale(), new numeric_only()));
        while ( std::cin >> num)
             std::cout << num << std::endl;
        return 0;
}

Texte de saisie:

 the format (-5) or (25) etc... some text.. and then.. 7987...78hjh.hhjg9878

Entiers de sortie:

 5
25
7987
78
9878

La classe numeric_onlyest définie comme:

struct numeric_only: std::ctype<char> 
{
    numeric_only(): std::ctype<char>(get_table()) {}

    static std::ctype_base::mask const* get_table()
    {
        static std::vector<std::ctype_base::mask> 
            rc(std::ctype<char>::table_size,std::ctype_base::space);

        std::fill(&rc['0'], &rc[':'], std::ctype_base::digit);
        return &rc[0];
    }
};

Démo complète en ligne: http://ideone.com/dRWSj


4

C'est probablement un peu exagéré, mais cela boost::lexical_cast<int>( theString )devrait très bien fonctionner.


Une faute de frappe. Il doit être simple boost::lexical_cast<int>( theString )(où theStringest le nom de la variable qui contient la chaîne que vous souhaitez convertir int).
James Kanze


1

Sous Windows, vous pouvez utiliser:

const std::wstring hex = L"0x13";
const std::wstring dec = L"19";

int ret;
if (StrToIntEx(hex.c_str(), STIF_SUPPORT_HEX, &ret)) {
    std::cout << ret << "\n";
}
if (StrToIntEx(dec.c_str(), STIF_SUPPORT_HEX, &ret)) {
    std::cout << ret << "\n";
}

strtol, vous stringstreamdevez spécifier la base si vous avez besoin d'interpréter hexadécimal.


1

Eh bien, beaucoup de réponses, beaucoup de possibilités. Ce qui me manque ici, c'est une méthode universelle qui convertit une chaîne en différents types intégraux C ++ (court, int, long, bool, ...). J'ai trouvé la solution suivante:

#include<sstream>
#include<exception>
#include<string>
#include<type_traits>

using namespace std;

template<typename T>
T toIntegralType(const string &str) {
    static_assert(is_integral<T>::value, "Integral type required.");
    T ret;
    stringstream ss(str);
    ss >> ret;
    if ( to_string(ret) != str)
        throw invalid_argument("Can't convert " + str);
    return ret;
}

Voici des exemples d'utilisation:

string str = "123";
int x = toIntegralType<int>(str); // x = 123

str = "123a";
x = toIntegralType<int>(str); // throws exception, because "123a" is not int

str = "1";
bool y = toIntegralType<bool>(str); // y is true
str = "0";
y = toIntegralType<bool>(str); // y is false
str = "00";
y = toIntegralType<bool>(str); // throws exception

Pourquoi ne pas simplement utiliser l'opérateur de sortie stringstream pour convertir une chaîne en un type intégral? Voici la réponse: disons qu'une chaîne contient une valeur qui dépasse la limite du type intégral voulu. Par exemple, sur Wndows 64 max int est 2147483647. Attribuons à une chaîne une valeur max int + 1: chaîne str = "2147483648". Maintenant, lors de la conversion de la chaîne en int:

stringstream ss(str);
int x;
ss >> x;

x devient 2147483647, ce qui est définitivement une erreur: la chaîne "2147483648" n'était pas censée être convertie en int 2147483647. La fonction fournie àIntegralType détecte ces erreurs et lève une exception.


0

De http://www.cplusplus.com/reference/string/stoi/

// stoi example
#include <iostream>   // std::cout
#include <string>     // std::string, std::stoi

int main ()
{
  std::string str_dec = "2001, A Space Odyssey";
  std::string str_hex = "40c3";
  std::string str_bin = "-10010110001";
  std::string str_auto = "0x7f";

  std::string::size_type sz;   // alias of size_t

  int i_dec = std::stoi (str_dec,&sz);
  int i_hex = std::stoi (str_hex,nullptr,16);
  int i_bin = std::stoi (str_bin,nullptr,2);
  int i_auto = std::stoi (str_auto,nullptr,0);

  std::cout << str_dec << ": " << i_dec << " and [" << str_dec.substr(sz) << "]\n";
  std::cout << str_hex << ": " << i_hex << '\n';
  std::cout << str_bin << ": " << i_bin << '\n';
  std::cout << str_auto << ": " << i_auto << '\n';

  return 0;
}

Production:

2001, A Space Odyssey: 2001 et [, A Space Odyssey]

40c3: 16579

-10010110001: -1201

0x7f: 127


0

Mon code:

#include <iostream>
using namespace std;

int main()
{
    string s="32";  //String
    int n=stoi(s);  //Convert to int
    cout << n + 1 << endl;

    return 0;
}

0
ll toll(string a){
    ll ret=0;
    bool minus=false;
    for(auto i:a){
        if(i=='-'){ minus=true; continue; }
        ret*=10;
        ret+=(i-'0');
    } if(minus) ret*=-1;
    return ret;
    # ll is defined as, #define ll long long int
    # usage: ll a = toll(string("-1234"));
}

0

Pour convertir de la représentation sous forme de chaîne en valeur entière, nous pouvons utiliser std :: stringstream.

si la valeur convertie est hors limites pour le type de données entier, elle renvoie INT_MIN ou INT_MAX.

De plus, si la valeur de chaîne ne peut pas être représentée comme un type de données int valide, 0 est renvoyé.

#include 
#include 
#include 

int main() {

    std::string x = "50";
    int y;
    std::istringstream(x) >> y;
    std::cout << y << '\n';
    return 0;
}

Sortie: 50

Selon la sortie ci-dessus, nous pouvons le voir converti des numéros de chaîne en nombre entier.

Source et plus à la chaîne en int c ++


-2

Version une ligne: long n = strtol(s.c_str(), NULL, base); .

( sest la chaîne et baseest unint telle que 2, 8, 10, 16.)

Vous pouvez vous référer à ce lien pour plus de détails strtol.


L'idée de base est d'utiliser la strtolfonction, qui est incluse danscstdlib .

Étant donné strtolque seules les poignées avec chartableau, nous devons convertir stringen chartableau. Vous pouvez vous référer à ce lien .

Un exemple:

#include <iostream>
#include <string>   // string type
#include <bitset>   // bitset type used in the output

int main(){
    s = "1111000001011010";
    long t = strtol(s.c_str(), NULL, 2); // 2 is the base which parse the string

    cout << s << endl;
    cout << t << endl;
    cout << hex << t << endl;
    cout << bitset<16> (t) << endl;

    return 0;
}

qui produira:

1111000001011010
61530
f05a
1111000001011010

-3

il existe un autre moyen simple: supposons que vous ayez un personnage comme c='4' vous pouvez donc effectuer l'une des étapes suivantes:

1er: int q

q=(int) c ; (q is now 52 in ascii table ) . q=q-48; remember that adding 48 to digits is their ascii code .

la deuxième façon:

q=c-'0'; the same , character '0' means 48


1
La question est de convertir de stringà intplutôt que de charà string.
Yuchen Zhong

buggy et ne correspondant pas à la question
caoanan
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.