Como posso converter um std :: string para int?


484

Basta ter uma pergunta rápida. Examinei bastante a Internet e encontrei algumas soluções, mas nenhuma delas funcionou ainda. Olhando para converter uma string em int e não quero dizer códigos ASCII.

Para uma rápida decomposição, somos passados ​​em uma equação como uma string. Devemos decompô-lo, formatá-lo corretamente e resolver as equações lineares. Agora, ao dizer isso, não consigo converter uma string em um int.

Eu sei que a string estará no formato (-5) ou (25) etc., por isso é definitivamente um int. Mas como extraímos isso de uma string?

Uma maneira que eu estava pensando em executar um loop for / while na string, verifique se há um dígito, extraia todos os dígitos depois disso e verifique se havia um '-' inicial, se houver, multiplique o int por - 1

Parece um pouco complicado demais para um problema tão pequeno. Alguma ideia?


9
Você já tentou atoi()?
precisa saber é o seguinte



7
@ Chad Então você está recomendando que ele use uma biblioteca inteira para algo que o idioma possa fazer com as bibliotecas padrão, afinal?
Bojangles

6
@Brandon, se você tem um std::string myStringe deseja usar atoi, então você quer dizer atoi(myString.c_str()).
Robᵩ

Respostas:


726

No C ++ 11, existem algumas novas e agradáveis ​​funções de conversão de std::stringpara um tipo de número.

Então, ao invés de

atoi( str.c_str() )

você pode usar

std::stoi( str )

Onde strestá o seu número como std::string.

Há versão para todos os sabores de números: long stol(string), float stof(string), double stod(string), ... ver http://en.cppreference.com/w/cpp/string/basic_string/stol


5
Para problemas com std :: stoi, consulte stackoverflow.com/a/6154614/195527 : ele será convertido "11x"em número inteiro 11.
CC.

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

4
@CC Esse também é o comportamento do atoi: cplusplus.com/reference/cstdlib/atoi "A string pode conter caracteres adicionais após os que formam o número inteiro , que são ignorados e não têm efeito no comportamento dessa função."
Assistente de Tin

4
Você se importaria de atualizar esta resposta from_charsdo C ++ 17? Supõe-se que sejam ordens de magnitude mais rápidas que stoi.
NathanOliver 29/07/19

stoideve ser preferido. Consulte Por que não devo usar atoi ()?
phuclv 18/01

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

Para estar totalmente correto, convém verificar os sinalizadores de erro.


2
Isso não será extraído -5de (-5).
Nawaz

@Nawaz, as parênteses estão realmente lá, ou é assim que o OP está apresentando suas seqüências?
Winston Ewert

Eu não sei. Estou apenas apontando a limitação da abordagem.
Nawaz

16
@Nawaz, também não pode operar na entrada "WERWER". Eu não acho que as parênteses sejam realmente parte de sua sequência real e não acho relevante o fato de não analisá-las.
Winston Ewert

4
@Nawaz, ok ... Eu não entendo a palavra dessa maneira, mas vejo como você poderia.
Winston Ewert

44

As opções possíveis estão descritas abaixo:

1. Primeira opção: 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

Este é um erro (também mostrado pelo cppcheck) porque "scanf sem limites de largura de campo pode travar com enormes dados de entrada em algumas versões da libc" (veja aqui e aqui ).

2. Segunda opção: 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
        }   

Essa solução é curta e elegante, mas está disponível apenas em compiladores compatíveis com C ++ 11.

3. Terceira opção: fluxos

    #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 ??

No entanto, com esta solução é difícil distinguir entre entrada incorreta (veja aqui ).

4. Quarta opção: lexical_cast da 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
        }

No entanto, este é apenas um invólucro sstreame a documentação sugere usarsstream para um melhor gerenciamento de erros (veja aqui ).

5. Quinta opção: strto * ()

Esta solução é muito longa, devido ao gerenciamento de erros, e é descrita aqui. Como nenhuma função retorna um int simples, é necessária uma conversão no caso de um número inteiro (consulte aqui como obter essa conversão).

6. Sexta opção: 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     

Conclusões

Resumindo, a melhor solução é o C ++ 11 std::stoi()ou, como segunda opção, o uso de bibliotecas Qt. Todas as outras soluções são desencorajadas ou com erros.


Fixo. Obrigado por denunciar.
Claudio

Resumo bonito, muito obrigado. Posso sugerir um comentário inicial sugerindo a solução final para que apenas as pessoas interessadas nos detalhes continuem lendo?
luca

1
esta deve ser a resposta aceita, igualmente você esqueceu (ou melhor, deve adicionar porque é uma resposta de idade) from_chars
Xception


9

E o Boost.Lexical_cast ?

Aqui está o exemplo deles:

O exemplo a seguir trata os argumentos da linha de comando como uma sequência de dados numéricos:

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);
        }
    }
    ...
}

O link está quebrado. Você poderia consertar isso?
Yuchen Zhong 07/03

5

É certo que minha solução não funcionaria para números inteiros negativos, mas extrairá todos os números inteiros positivos do texto de entrada que contém números inteiros. Faz uso do numeric_onlycódigo do idioma:

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

Entrada de texto:

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

Inteiros de saída:

 5
25
7987
78
9878

A classe numeric_onlyé definida como:

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];
    }
};

Demonstração on-line completa: http://ideone.com/dRWSj


4

Provavelmente é um pouco exagerado, mas boost::lexical_cast<int>( theString )deve funcionar muito bem.


Um erro de digitação. Deve ser simples boost::lexical_cast<int>( theString )(onde theStringé o nome da variável que contém a string que você deseja converter int).
quer


1

No Windows, você pode usar:

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, é stringstreamnecessário especificar a base se você precisar interpretar hexdecimal.


1

Bem, muitas respostas, muitas possibilidades. O que estou perdendo aqui é algum método universal que converte uma string em diferentes tipos integrais de C ++ (short, int, long, bool, ...). Eu vim com a seguinte solução:

#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;
}

Aqui estão alguns exemplos de uso:

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

Por que não usar o operador de saída stringstream para converter uma string em um tipo integral? Aqui está a resposta: Digamos que uma string contenha um valor que exceda o limite para o tipo integral pretendido. Por exemplo, no Wndows 64 max int é 2147483647. Vamos atribuir a uma string um valor max int + 1: string str = "2147483648". Agora, ao converter a string em um int:

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

x se torna 2147483647, o que definitivamente é um erro: a string "2147483648" não deveria ser convertida na int 2147483647. A função fornecida toIntegralType identifica esses erros e gera uma exceção.


0

Em 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;
}

Resultado:

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

40c3: 16579

-10010110001: -1201

0x7f: 127


0

Meu código:

#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

Para converter de representação de string em valor inteiro, podemos usar std :: stringstream.

se o valor convertido estiver fora do intervalo para o tipo de dados inteiro, ele retornará INT_MIN ou INT_MAX.

Além disso, se o valor da sequência não puder ser representado como um tipo de dados int válido, será retornado 0.

#include 
#include 
#include 

int main() {

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

Saída: 50

De acordo com a saída acima, podemos vê-lo convertido de números de string em número inteiro.

Origem e mais na string para int c ++


-2

Versão de uma linha: long n = strtol(s.c_str(), NULL, base); .

( sé a sequência e baseé int2, 8, 10, 16.)

Você pode consultar este link para obter mais detalhes sobre strtol.


A idéia principal é usar a strtolfunção, incluída em cstdlib.

Como strtolapenas lida com charmatriz, precisamos converter stringem charmatriz. Você pode consultar este link .

Um exemplo:

#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;
}

que produzirá:

1111000001011010
61530
f05a
1111000001011010

-3

existe outra maneira fácil: suponha que você tenha um personagem como c='4' portanto, você pode executar uma destas etapas:

1º: 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 .

a segunda maneira:

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


1
A questão é sobre a conversão de stringpara intem vez de charpara string.
Yuchen Zhong 29/05

buggy e que não corresponde a questão
caoanan
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.