Як я можу перетворити std :: string в int?


484

Просто швидке запитання. Я переглянув Інтернет досить небагато і знайшов кілька рішень, але жодне з них ще не працювало. Дивлячись на перетворення рядка в int, і я не маю на увазі коди ASCII.

Для швидкого запуску ми передаємося в рівняння як рядок. Ми повинні розбити її, відформатувати її правильно та вирішити лінійні рівняння. Тепер, кажучи про це, я не в змозі перетворити рядок в int.

Я знаю, що рядок буде у форматі (-5) або (25) тощо, тому це, безумовно, int. Але як ми витягуємо це з рядка?

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

Однак це здається трохи складним для такої невеликої проблеми. Будь-які ідеї?


9
Ви пробували atoi()?
i_am_jorf



7
@Chad Тож ви рекомендуєте йому використовувати цілу бібліотеку для чогось, що мова може робити зі стандартними бібліотеками?
Bojangles

6
@Brandon, якщо у вас є std::string myStringі хочете використовувати atoi, тоді ви хочете сказати atoi(myString.c_str()).
Robᵩ

Відповіді:


726

У 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 * /
Ulad Kasach

4
@CC Це також поведінка atoi: cplusplus.com/reference/cstdlib/atoi "Рядок може містити додаткові символи після тих, що утворюють інтегральне число, які ігноруються і не впливають на поведінку цієї функції."
Чарівний майстер

4
Ви б не хотіли б оновити цю відповідь за from_charsдопомогою C ++ 17? Це повинно бути на порядок швидше, ніж stoi.
NathanOliver

stoiслід віддати перевагу. Див. Чому я не повинен використовувати atoi ()?
phuclv

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

Щоб повністю коректувати, ви хочете перевірити прапори помилок.


2
Це не буде витягнуто -5з (-5).
Наваз

@Nawaz, пареї насправді є, чи це так, як ОП представляє свої рядки?
Вінстон Еверт

Не знаю. Я просто вказую на обмеженість підходу.
Наваз

16
@Nawaz, він також не може працювати на вході "WERWER". Я не думаю, що парени насправді є частиною його фактичної струни, і я не думаю, що факт, що я їх не розбираю, є релевантним.
Вінстон Еверт

4
@Nawaz, добре ... Я не сприймаю цього слова, але я бачу, як ти міг.
Вінстон Еверт

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. Четвертий варіант: Leostical_cast 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 ++ (цілі, 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

Чому б просто не використовувати оператор виводу потокового потоку для перетворення рядка в цілісний тип? Ось відповідь: Скажімо, рядок містить значення, яке перевищує межу призначеного інтегрального типу. Для іспиту на 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 та [, Космічна Одісея]

40c3: 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

Згідно з наведеним вище висновком, ми можемо бачити, що він перетворюється з рядкових чисел у цілі числа.

Джерело та інше в рядку до int 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.