如何将std :: string转换为int?

758

我想将一个字符串转换为整数,而不是ASCII码。

简单来说,我们会得到一个字符串方程。我们需要将其分解,正确格式化并解决线性方程。但是,我无法将字符串转换为整数。

我知道这个字符串的格式将是(-5)或(25)等,因此它一定是整数。但是如何从一个字符串中提取出它呢?

我考虑的一个方法是通过字符串运行for / while循环,检查数字,提取其后的所有数字,然后查看是否有前导'-',如果有,则将整数乘以-1。

但对于这样一个小问题来说,似乎有点过于复杂了。你们有什么好主意吗?


12
你尝试过使用atoi()函数吗? - i_am_jorf
3
好的,我会尽力进行翻译。以下是您提供链接中的内容:函数原型:int atoi (const char* str);功能:将参数 str 所指向的字符串转换为一个整数(类型为 int)。返回值:如果转换成功,则返回该整数,否则返回零。注意事项:
  • 该函数会跳过字符串开头的空格字符。
  • 当遇到非数字字符时,停止转换,返回当前已经转换的整数值。
  • 如果转换后的整数超出了 int 类型的范围,则返回 INT_MAXINT_MIN,具体取决于转换结果的符号。
示例用法:/* atoi examples */ #include /* printf */ #include /* atoi */ int main () { int i; char buffer[256]; printf ("Enter a number: "); fgets (buffer, 256, stdin); i = atoi (buffer); printf ("The value entered is %d. Its double is %d.\n",i,i*2); return 0; }
- i_am_jorf
2
http://stackoverflow.com/search?q=convert+string+int++c%2B%2B - Kiril Kirov
9
那么你建议他为一些标准库已经能够完成的事情使用整个库吗?@Chad - Bojangles
8
如果你有一个名为 myStringstd::string,而想要使用 atoi 函数,则需要输入 atoi(myString.c_str()) - Robᵩ
显示剩余7条评论
26个回答

1102

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


12
有关std::stoi的问题,请参见https://dev59.com/yXVC5IYBdhLWcg3wvT_g#6154614:它将把“11x”转换为整数11。 - CC.
5
包含<stdlib.h>头文件,其中包括函数atoi。 - Ulad Kasach
9
这也是atoi的行为:http://www.cplusplus.com/reference/cstdlib/atoi/ "字符串可以包含整数数字之后的其他字符,这些字符将被忽略,并且不会影响该函数的行为。" - Tin Wizard
8
请问您能否用C++17的from_chars更新这个答案?它应该比stoi快几个数量级。 - NathanOliver
但是如果你执行 std::stoi("not-a-num"),会导致程序崩溃,你该怎么办? - Yongqi Z
显示剩余3条评论

110

以下是可能的选项:

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

然而,这种解决方案很难区分错误的输入(请参见此处)。

4. Boost 的 lexical_cast

    #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()*

由于需要进行错误管理,因此该解决方案非常冗长,可在此处找到其描述。由于没有任何函数返回普通整数,所以在需要整数的情况下需要进行转换(请参见此处了解如何进行转换)。

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 库。其他所有解决方案都不被鼓励,或者存在漏洞。


已修复。感谢您的反馈。 - Claudio
非常感谢您的精彩总结。我可以建议添加一个初始评论,建议最终解决方案,以便只有对细节感兴趣的人才会继续阅读吗? - luca
2
这应该是被接受的答案,同时你忘了(或者更确切地说应该添加,因为它是一个旧答案)from_chars。 - xception
不要使用 sscanf。这是一个 C API 函数,而问题涉及到 C++。如果您打算使用 sscanf,请至少使用 std:: - Marc Dirven

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

为了完全正确,您需要检查错误标志。


2
这将不会从(-5)中提取-5 - Nawaz
我不知道。我只是指出这种方法的局限性。 - Nawaz
@Nawaz,那不是真正的限制,而是需要进行预处理以摆脱括号。 - Winston Ewert
20
@Nawaz,它也无法处理输入“WERWER”。我认为括号实际上不是他实际字符串的一部分,而且我不认为我不解析它们是相关的。 - Winston Ewert
4
@Nawaz,好的...我不是那样理解这个词,但我可以理解你的看法。 - Winston Ewert
显示剩余3条评论

54
为了更加详尽(正如评论中所要求的),我添加了使用 C++17 提供的 std::from_chars 解决方案。
std::string str = "10";
int number;
std::from_chars(str.data(), str.data()+str.size(), number);

如果您想要检查转换是否成功:
std::string str = "10";
int number;
auto [ptr, ec] = std::from_chars(str.data(), str.data()+str.size(), number);
assert(ec == std::errc{});
// ptr points to chars after read number

此外,为了比较所有解决方案的性能,请参见 this quick-bench link。其中,std::from_chars 是最快的,而std::istringstream 则最慢。

这是最干净的解决方案。 - Quimby
值得一提的是,这也允许使用除10以外的进制,这是好老的atoi所没有提供的一个特性。 - Wolf

51
使用atoi函数将字符串转换为整数:
string a = "25";

int b = atoi(a.c_str());

17
永远不要使用 atoistrtol 能够完成 atoi 的所有功能,而且更加安全可靠。 - Ben Voigt
扩展@BenVoigt的评论:避免使用atoi的一个重要原因是它仅通过返回0来报告转换失败! atoi不会不安全地失败,而是_默默失败_。 - Vainstein K
1
@VainsteinK:有些故障通过返回0来报告。其他一些会导致atoi出现未定义的行为。这使得它对于验证不受信任的输入毫无用处。https://wiki.sei.cmu.edu/confluence/display/c/ERR07-C.+Prefer+functions+that+support+error+checking+over+equivalent+functions+that+don%27t - Ben Voigt

14

1. std::stoi()

std::string str = "10";
int number = std::stoi(str);

2. 字符串流

std::string str = "10";
int number;
std::istringstream(str) >> number;

3. boost::lexical_cast

#include <boost/lexical_cast.hpp>
std::string str = "10";
int number;

try
{
    number = boost::lexical_cast<int>(str);
    std::cout << number << std::endl;
}
catch (boost::bad_lexical_cast const &e) // Bad input
{
    std::cout << "error" << std::endl;
}

4. std::atoi()

std::string str = "10";
int number = std::atoi(str.c_str());

5. sscanf()

std::string str = "10";
int number;
if (sscanf(str .c_str(), "%d", &number) == 1)
{
    std::cout << number << '\n';
}
else
{
    std::cout << "Bad Input";
}

10

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

链接已经失效了。你能修复一下吗? - Yuchen

7

诚然,我的解决方案不能处理负整数,但它可以从包含整数的输入文本中提取所有正整数。它利用了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

6
在C++11中,我们可以使用"stoi"函数将字符串转换为整数。
#include <iostream>
#include <string>
using namespace std;
 
int main()
{
    string s1 = "16";
    string s2 = "9.49";
    string s3 = "1226";
 
    int num1 = stoi(s1);
    int num2 = stoi(s2);
    int num3 = stoi(s3);
 
    cout << "stoi(\"" << s1 << "\") is " << num1 << '\n';
    cout << "stoi(\"" << s2 << "\") is " << num2 << '\n';
    cout << "stoi(\"" << s3 << "\") is " << num3 << '\n';
 
    return 0;
}

4

这可能有点过度设计,但 boost::lexical_cast<int>( theString ) 应该能够很好地完成工作。


一个笔误。应该是简单的 boost::lexical_cast<int>(theString)(其中 theString 是包含要转换为 int 的字符串的变量名称)。 - James Kanze

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接