Как я могу преобразовать std :: string в int?


485

Просто быстрый вопрос. Я немного осмотрел интернет и нашел несколько решений, но ни одно из них еще не сработало. Глядя на преобразование строки в int, я не имею в виду ASCII-коды.

Для быстрого перехода мы передаем уравнение в виде строки. Мы должны разбить его, правильно отформатировать и решить линейные уравнения. Теперь, говоря это, я не могу преобразовать строку в int.

Я знаю, что строка будет в формате (-5) или (25) и т. Д., Так что это определенно int. Но как нам извлечь это из строки?

Один из способов, которым я думал, это запустить цикл for / while через строку, проверить наличие цифры, извлечь все цифры после этого и затем посмотреть, есть ли начальный '-', если есть, умножить int на - 1.

Это кажется слишком сложным для такой маленькой проблемы. Любые идеи?


9
Ты пробовал atoi()?
i_am_jorf



7
@ Чед Итак, вы рекомендуете использовать целую библиотеку для того, что язык может делать со стандартными библиотеками?
Bojangles

6
@ Брэндон, если у вас есть std::string myString, и вы хотите использовать atoi, то вы хотите сказать atoi(myString.c_str()).
Робо

Ответы:


727

В C ++ 11 есть несколько хороших новых функций преобразования std::stringв числовой тип.

Так что вместо

atoi( str.c_str() )

ты можешь использовать

std::stoi( str )

где strваш номер как std::string.

Есть версия для всех вкусов чисел: long stol(string), float stof(string), double stod(string), ... см http://en.cppreference.com/w/cpp/string/basic_string/stol


5
Для проблем с std :: stoi см. Stackoverflow.com/a/6154614/195527 : он преобразуется "11x"в целое число 11.
СС.

5
#include <stdlib.h> / * atoi * /
Улад Касач

4
@CC Это также поведение atoi: cplusplus.com/reference/cstdlib/atoi «Строка может содержать дополнительные символы после тех, которые образуют целое число, которые игнорируются и не влияют на поведение этой функции».
Оловянный волшебник

4
Не могли бы вы обновить этот ответ с from_charsC ++ 17? Предполагается, что это будет на порядок быстрее, чем stoi.
Натан Оливер

stoiдолжно быть предпочтительным. См. Почему я не должен использовать atoi ()?
phuclv

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

Чтобы быть полностью правильным, вы захотите проверить флаги ошибок.


2
Это не будет извлекать -5из (-5).
Наваз

@ Наваз, действительно ли присутствуют парены, или это просто то, как ОП представляет свои строки?
Уинстон Эверт

Я не знаю. Я просто указываю на ограничение подхода.
Наваз

16
@Nawaz, он также не может работать на входе "WERWER". Я не думаю, что паренсы на самом деле являются частью его настоящей строки, и я не думаю, что тот факт, что я их не анализирую, имеет значение.
Уинстон Эверт

4
@ Наваз, ладно ... Я так не понимаю, но вижу, как ты мог.
Уинстон Эверт

44

Возможные варианты описаны ниже:

1. Первый вариант: 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

Это ошибка (также показанная cppcheck), потому что «scanf без ограничений ширины поля может привести к сбою с огромными входными данными в некоторых версиях libc» (см. Здесь и здесь ).

2. Второй вариант: 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
        }   

Это короткое и элегантное решение, но оно доступно только на компиляторах, совместимых с C ++ 11.

3. Третий вариант: потоки

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

Однако при таком решении трудно отличить плохой ввод (см. Здесь ).

4. Четвертый вариант: лексическая трансляция 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
        }

Тем не менее, это просто оболочка sstream, и документация предлагает использовать sstreamдля лучшего управления ошибками (см. Здесь ).

5. Пятый вариант: strto * ()

Это решение очень длинное из-за управления ошибками, и оно описано здесь. Поскольку ни одна функция не возвращает обычное значение int, необходимо преобразование в случае целого числа (см. Здесь, как это преобразование может быть достигнуто).

6. Шестой вариант: 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     

Выводы

Подводя итог, можно сказать, что лучшим решением является C ++ 11 std::stoi()или, в качестве второго варианта, использование библиотек Qt. Все остальные решения не приветствуются или содержат ошибки.


Исправлена. Спасибо за сообщение.
Клаудио

Красивое резюме, большое спасибо. Могу ли я предложить добавить первоначальный комментарий, предлагающий окончательное решение, чтобы только люди, заинтересованные в деталях, продолжали читать?
Лука

1
это должен быть принятый ответ, также вы забыли (или, скорее, должны добавить, потому что это старый ответ) from_chars
xception


9

А как насчет Boost.Lexical_cast ?

Вот их пример:

В следующем примере аргументы командной строки обрабатываются как последовательность числовых данных:

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

Ссылка не работает. Не могли бы вы это исправить?
Ючен Чжун

5

По общему признанию, мое решение не будет работать для отрицательных целых чисел, но оно извлечет все положительные целые числа из входного текста, содержащего целые числа. Это использует numeric_onlyязык:

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

Введите текст:

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

Выходные целые числа:

 5
25
7987
78
9878

Класс numeric_onlyопределяется как:

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

Полная онлайн-демонстрация: http://ideone.com/dRWSj


4

Это, вероятно, немного излишне, но boost::lexical_cast<int>( theString )должно хорошо работать.


Опечатка. Это должно быть просто boost::lexical_cast<int>( theString )(где theStringимя переменной, которая содержит строку, в которую вы хотите преобразовать int).
Джеймс Канз


1

В Windows вы можете использовать:

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, stringstreamнеобходимо указать базу, если вам нужно интерпретировать шестнадцатеричное.


1

Ну, много ответов, много возможностей. Здесь мне не хватает универсального метода, который преобразует строку в различные целочисленные типы C ++ (short, int, long, bool, ...). Я придумал следующее решение:

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

Вот примеры использования:

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

Почему бы просто не использовать оператор вывода stringstream для преобразования строки в целочисленный тип? Вот ответ: допустим, строка содержит значение, которое превышает предел для целевого целевого типа. Например, в Wndows 64 max int равно 2147483647. Давайте присвоим строке значение max int + 1: string str = "2147483648". Теперь при преобразовании строки в int:

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

x становится 2147483647, что определенно является ошибкой: строка «2147483648» не должна была быть преобразована в int 2147483647. Предоставленная функция toIntegralType обнаруживает такие ошибки и выдает исключение.


0

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

Вывод:

2001, Космическая Одиссея: 2001 и [, Космическая Одиссея]

40с3: 16579

-10010110001: -1201

0x7f: 127



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

Чтобы преобразовать строковое представление в целочисленное значение, мы можем использовать std :: stringstream.

если преобразованное значение выходит за пределы диапазона для целочисленного типа данных, он возвращает INT_MIN или INT_MAX.

Также, если строковое значение не может быть представлено как допустимый тип данных int, возвращается 0.

#include 
#include 
#include 

int main() {

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

Выход: 50

Согласно приведенному выше выводу, мы можем видеть его преобразованным из строковых чисел в целое число.

Исходный код и многое другое в строке к C ++


-2

Одна линия версия: long n = strtol(s.c_str(), NULL, base);.

( sЭто строка, и baseпредставляет собой , intнапример , как 2, 8, 10, 16.)

Вы можете обратиться к этой ссылке для более подробной информации strtol.


Основная идея заключается в использовании strtolфункции, которая включена в cstdlib.

Так как strtolобрабатываются только с charмассивом, нам нужно преобразовать stringв charмассив. Вы можете обратиться к этой ссылке .

Пример:

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

который выведет:

1111000001011010
61530
f05a
1111000001011010

-3

Есть еще один простой способ: предположим, у вас есть такой персонаж, c='4'поэтому вы можете сделать один из следующих шагов:

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 .

второй способ:

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


1
Речь идет о переходе от stringк , intа не от charк string.
Ючен Чжун

глючит и не соответствует вопросу
caoanan
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.