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

Bra*_*don 438 c++ string int

只是有一个简短的问题.我已经在互联网上看了很多,我找到了一些解决方案,但没有一个已经有效.看一下将字符串转换为int,我不是指ASCII码.

为了快速减少,我们将方程作为字符串传递.我们要将其分解,正确格式化并求解线性方程.现在,在说,我无法将字符串转换为int.

我知道字符串将采用格式(-5)或(25)等,所以它肯定是一个int.但是我们如何从字符串中提取它?

我想的一种方法是通过字符串运行for/while循环,检查一个数字,然后提取所有数字,然后查看是否有一个前导' - ',如果存在,则将int乘以 - 1.

虽然这个小问题看起来有点过于复杂.有任何想法吗?

tgm*_*ath 658

在C++ 11中,有一些很好的新转换函数从std::string数字类型.

而不是

atoi( str.c_str() )
Run Code Online (Sandbox Code Playgroud)

您可以使用

std::stoi( str )
Run Code Online (Sandbox Code Playgroud)

str你的号码在哪里std::string.

有版本号的所有口味: long stol(string),float stof(string),double stod(string),...查看http://en.cppreference.com/w/cpp/string/basic_string/stol

  • 您介意用 C++17 中的“from_chars”更新这个答案吗?它应该比“stoi”快几个数量级。 (5认同)
  • 有关std :: stoi的问题,请参阅http://stackoverflow.com/a/6154614/195527:它会将"11x"转换为整数"11". (4认同)
  • #include <stdlib.h>/*atoi*/ (4认同)
  • @CC这也是atoi的行为:http://www.cplusplus.com/reference/cstdlib/atoi/"字符串可以包含在形成整数的字符之后的其他字符,这些字符被忽略并且对行为没有影响这个功能." (4认同)

Win*_*ert 58

std::istringstream ss(thestring);
ss >> thevalue;
Run Code Online (Sandbox Code Playgroud)

要完全正确,您需要检查错误标志.

  • @Nawaz,它也无法对输入"WERWER"进行操作.我不认为parens实际上是他的实际字符串的一部分,我不认为我不解析它们的事实是相关的. (14认同)
  • @Nawaz,好的......我不这么说,但我知道你怎么做. (4认同)
  • 这不会从`( - 5)`中提取`-5`. (2认同)

bre*_*njt 37

使用atoi函数将字符串转换为整数:

string a = "25";

int b = atoi(a.c_str());
Run Code Online (Sandbox Code Playgroud)

http://www.cplusplus.com/reference/clibrary/cstdlib/atoi/

  • 永远不要使用`atoi`.`strtol`做的一切都是'atoi`做的,但更好,并且安全失败. (13认同)
  • @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 (2认同)

Cla*_*dio 35

可能的选项如下所述:

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
Run Code Online (Sandbox Code Playgroud)

这是一个错误(也由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(s);

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

            // string -> double 
            double d = std::stod(s);
        } catch (...) {
            // error management
        }   
Run Code Online (Sandbox Code Playgroud)

此解决方案简短而优雅,但仅适用于C++ 11 compliants编译器.

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 ??
Run Code Online (Sandbox Code Playgroud)

但是,使用此解决方案很难区分不良输入(请参阅此处).

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
        }
Run Code Online (Sandbox Code Playgroud)

但是,这只是sstream的包装,文档建议使用sstrem进行更好的错误管理(参见此处).

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     
Run Code Online (Sandbox Code Playgroud)

结论

总而言之,最好的解决方案是C++ 11 std :: stoi(),或者作为第二种选择,使用Qt库.所有其他解决方案都不鼓励或错误.

  • 这应该是公认的答案,你也忘记了(或者应该添加,因为它是一个旧答案)from_chars (2认同)

use*_*747 14

1.std::stoi()

std::string str = "10";
int number = std::stoi(str);
Run Code Online (Sandbox Code Playgroud)

2. 字符串流

std::string str = "10";
int number;
std::istringstream(str) >> number;
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

4.std::atoi()

std::string str = "10";
int number = std::atoi(str.c_str());
Run Code Online (Sandbox Code Playgroud)

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";
}
Run Code Online (Sandbox Code Playgroud)


Pas*_* H. 11

为了更加详尽(正如评论中所要求的那样),我使用std::from_chars.

std::string str = "10";
int number;
std::from_chars(str.data(), str.data()+str.size(), number);
Run Code Online (Sandbox Code Playgroud)

如果要检查转换是否成功:

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
Run Code Online (Sandbox Code Playgroud)

此外,要比较所有这些解决方案的性能,请参阅以下快速基准链接:https : //quick-bench.com/q/GBzK53Gc-YSWpEA9XskSZLU963Y

std::from_chars是最快的,std::istringstream也是最慢的)


Rob*_*obᵩ 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);
        }
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)


小智 6

在C++11中,我们可以使用“stoi”函数将字符串转换为int

#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;
}
Run Code Online (Sandbox Code Playgroud)


Naw*_*waz 5

不可否认,我的解决方案不适用于负整数,但它将从包含整数的输入文本中提取所有正整数.它使用numeric_onlylocale:

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;
}
Run Code Online (Sandbox Code Playgroud)

输入文本:

 the format (-5) or (25) etc... some text.. and then.. 7987...78hjh.hhjg9878
Run Code Online (Sandbox Code Playgroud)

输出整数:

 5
25
7987
78
9878
Run Code Online (Sandbox Code Playgroud)

该类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];
    }
};
Run Code Online (Sandbox Code Playgroud)

完整的在线演示:http://ideone.com/dRWSj


Jan*_*tke 5

C++ 随着时间的推移而发展,解析方法也随之发展int。\n我将在此答案中提供摘要。

\n

注意:答案同样适用于longfloat、 和其他算术类型。

\n

比较

\n

下表按最新到最新的顺序比较了所有选项(仅 C++ 标准选项,无第三方库)。

\n
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
方法错误处理优点缺点
std::from_chars
std::from_chars_result
(手动错误处理)
\xe2\x9c\x94\xef\xb8\x8f 快速且零开销
\xe2\x9c\x94\xef\xb8\x8f 支持任何基数作为运行时参数
\xe2\x9c\x94\xef\xb8\x8f 也可以对于浮点数,选择的格式
\xe2\x9d\x8c 界面不符合人体工程学
\xe2\x9d\x8c 没有区域设置支持
std::sto*系列
std::invalid_argument
std::out_of_range
(例外)
\xe2\x9c\x94\xef\xb8\x8f 简单接口
\xe2\x9c\x94\xef\xb8\x8f 支持任何基数作为运行时参数
\xe2\x9c\x94\xef\xb8\x8f 也适用于浮点数
\xe2\x9c\x94\xef\xb8\x8f 快乐路径中没有开销
\xe2\x9d\x8c 如果错误常见则效率低下
\xe2\x9d\x8c 晦涩的名称
\xe2\x9d\x8c 没有语言环境支持
std::istringstream
bool旗帜,或
stream.exceptions()
\xe2\x9c\x94\xef\xb8\x8f 通用方法(对于带有>>运算符的类型)
\xe2\x9c\x94\xef\xb8\x8f 考虑区域设置(例如可以更改基数)
\xe2\x9c\x94\xef\xb8 \x8f 可以检测不同的格式(例如0x...
\xe2\x9d\x8c 流的速度慢且开销高
\xe2\x9d\x8c 对不同基数的支持有限
std::strto*系列
std::errno
(全局标志、手册)
\xe2\x9c\x94\xef\xb8\x8f 小程序集输出
\xe2\x9c\x94\xef\xb8\x8f 快乐/悲伤路径中的小开销
\xe2\x9c\x94\xef\xb8\x8f 支持任何基数运行时参数
\xe2\x9c\x94\xef\xb8\x8f 与 C 兼容
\xe2\x9c\x94\xef\xb8\x8f 也适用于浮点数
\xe2\x9c\x94\xef\xb8\x8f 支持语言环境
\如果基数为零, xe2\x9c\x94\xef\xb8\x8f 可以检测不同的格式
\xe2\x9d\x8c 模糊名称
\xe2\x9d\x8c 界面不符合人体工程学
std::ato*家族
零表示失败
(手动错误处理)
\xe2\x9c\x94\xef\xb8\x8f 小汇编输出
\xe2\x9c\x94\xef\xb8\x8f 简单接口
\xe2\x9c\x94\xef\xb8\x8f 快乐/悲伤路径中的小开销
\xe2 \x9c\x94\xef\xb8\x8f 与 C 兼容
\xe2\x9c\x94\xef\xb8\x8f 也适用于浮点数
\xe2\x9d\x8c 模糊名称
\xe2\x9d\x8c int,不支持基数,格式等
std::sscanf
int
解析的参数数量
(手动错误处理)
\xe2\x9c\x94\xef\xb8\x8f 小汇编输出
\xe2\x9c\x94\xef\xb8\x8f 也适用于浮点数
\xe2\x9c\x94\xef\xb8\x8f 可以检测不同的格式(例如0x...
\ xe2\x9c\x94\xef\xb8\x8f 与 C 兼容
\xe2\x9d\x8c 接口不符合人体工程学
\xe2\x9d\x8c 无类型安全性,非常容易出现错误
\xe2\x9d\x8c 对不同基数的支持有限
\n

推荐做法

\n
    \n
  • 如果您有高性能应用程序,则使用std::from_chars, 或(如果不可用)。\n或std::strto*中的异常开销是不可接受的。std::sto*std::istringstream
  • \n
  • 否则,如果您需要 C 兼容性,请使用std::strto*.
  • \n
  • 否则,如果您的项目禁止例外,请使用std::istringstream.
  • \n
  • 否则,使用std::sto*,或创建一个围绕 的包装器std::from_chars
  • \n
\n

大多数特殊情况不太可能出现,因此大多数时候,使用std::stoiorstd::from_chars包装器

\n
// could be generalized with a template\nbool parse_int(std::string_view str, int& out, int base = 10) {\n    auto [ptr, err] = std::from_chars(str.data(), str.data() + str.size(), out, base);\n    return err == std::errc{};\n}\n\nstd::string s = ...;\nif (int x; parse_int(s, x)) {\n    // x has been parsed :)\n}\n
Run Code Online (Sandbox Code Playgroud)\n

这种包装器的优点是您始终可以回退到 C++17 之前的其他函数,同时始终具有相同的接口:

\n
// alternative pre-C++17 version\nbool parse_int(const std::string& str, int& out, int base = 10) {\n    errno = 0;\n    char* end = nullptr;\n    out = std::strtol(str.data(), str.data() + str.size(), &end, base);\n    return str.data() != end && errno == 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

如果你不关心这一点,你也可以返回parse_intstd::optional<int>不是分配引用。

\n