我有std::string
,可以是字符串,也可以是值(例如0
)。
将std::string
转换为int
并失败的最佳或最简单方法是什么?我想要C#的Int32.TryParse
的C ++版本。
答案 0 :(得分:42)
使用boost::lexical_cast。如果无法完成投射,它将throw an exception。
#include <boost/lexical_cast.hpp>
#include <iostream>
#include <string>
int main(void)
{
std::string s;
std::cin >> s;
try
{
int i = boost::lexical_cast<int>(s);
/* ... */
}
catch(...)
{
/* ... */
}
}
没有提升:
#include <iostream>
#include <sstream>
#include <string>
int main(void)
{
std::string s;
std::cin >> s;
try
{
std::stringstream ss(s);
int i;
if ((ss >> i).fail() || !(ss >> std::ws).eof())
{
throw std::bad_cast();
}
/* ... */
}
catch(...)
{
/* ... */
}
}
假装提升:
#include <iostream>
#include <sstream>
#include <string>
template <typename T>
T lexical_cast(const std::string& s)
{
std::stringstream ss(s);
T result;
if ((ss >> result).fail() || !(ss >> std::ws).eof())
{
throw std::bad_cast();
}
return result;
}
int main(void)
{
std::string s;
std::cin >> s;
try
{
int i = lexical_cast<int>(s);
/* ... */
}
catch(...)
{
/* ... */
}
}
如果你想要这些函数的无抛出版本,你必须捕获适当的异常(我不认为boost::lexical_cast
提供了无抛出版本),如下所示:
#include <iostream>
#include <sstream>
#include <string>
template <typename T>
T lexical_cast(const std::string& s)
{
std::stringstream ss(s);
T result;
if ((ss >> result).fail() || !(ss >> std::ws).eof())
{
throw std::bad_cast();
}
return result;
}
template <typename T>
bool lexical_cast(const std::string& s, T& t)
{
try
{
// code-reuse! you could wrap
// boost::lexical_cast up like
// this as well
t = lexical_cast<T>(s);
return true;
}
catch (const std::bad_cast& e)
{
return false;
}
}
int main(void)
{
std::string s;
std::cin >> s;
int i;
if (!lexical_cast(s, i))
{
std::cout << "Bad cast." << std::endl;
}
}
答案 1 :(得分:9)
即使字符串在有效数字后包含无效字符,使用流的其他答案也会成功,例如“123ABC”。我不熟悉boost,所以无法评论它的行为。
如果您想知道字符串是否包含数字而只包含数字,则必须使用strtol:
#include <iostream>
#include <string>
int main(void)
{
std::string s;
std::cin >> s;
char *end;
long i = strtol( s.c_str(), &end, 10 );
if ( *end == '\0' )
{
// Success
}
else
{
// Failure
}
}
strtol返回指向结束解析的字符的指针,因此您可以轻松检查是否已解析整个字符串。
请注意,strtol返回long而不是int,但根据您的编译器,这些可能是相同的。标准库中没有strtoi函数,只有atoi,它不返回解析结束字符。
答案 2 :(得分:7)
使用标准流的另一种方式:
#include <sstream>
#include <iostream>
#include <string>
int main()
{
std::stringstream convertor;
std::string numberString = "Not a number!";
int number;
convertor << numberString;
convertor >> number;
if(convertor.fail())
{
// numberString is not a number!
std::cout << "Not a Number!";
}
}
答案 3 :(得分:7)
对于被问到的问题,接受的答案确实是一个可怕的答案,因为它违反了规则&#34;对例外情况使用例外情况&#34;。
例外是处理特殊情况的绝佳工具 - 某些事情确实出错了。它们是现有用例的糟糕工具。部分原因是抛出和捕获异常是昂贵的,部分是因为它是误导性的代码 - 当开发人员看到异常时,他们应该合理地能够假设某些东西出错了。对这个基本原则的良好讨论比比皆是,但我喜欢&#34;实用程序员&#34;,或者这不是坏事:http://www.lohmy.de/2013/03/06/writing-use-cases-exception-or-alternate-flow/
boost :: lexical_cast是一个最佳解决方案,当它真正是一个例外,它接收一个非数字。
如果你正在浏览一个字符串并想要做一件事,如果它是一个数字,而另一件事如果它是一个数字,不要使用布尔测试的例外< / em>的。这只是糟糕的编程。
实际上,boost提供了try_lexical_convert,它用于lexical_cast的实现(取自这里的文档: http://www.boost.org/doc/libs/1_58_0/doc/html/boost_lexical_cast/synopsis.html#boost_lexical_cast.synopsis.lexical_cast)。
template <typename Target, typename Source>
inline Target lexical_cast(const Source &arg)
{
Target result;
if (!conversion::try_lexical_convert(arg, result))
throw bad_lexical_cast();
return result;
}
答案 4 :(得分:2)
在提升lexical_cast
之前,我曾经做过以下事情:
namespace detail {
template< typename Target, typename Source >
struct stream_caster {
static Target stream_cast(const Source& s)
{
std::stringstream ss;
if( (ss << s).fail() ) {
throw std::bad_cast("could not stream from source");
}
Target t;
if( (ss >> t).fail() || !(ss >> ws).eof) {
throw std::bad_cast("could not stream to target");
}
return t;
}
};
template< typename T >
struct stream_caster<T,T> {
static const T& stream_cast(const T& s)
{
return s;
}
};
template< typename Source >
struct stream_caster<std::string,Source> {
static std::string stream_cast(const Source& s)
{
std::ostringstream oss;
if( (oss << s).fail() ) {
throw std::bad_cast("could not stream from source");
}
return oss.str();
}
};
template< typename Target >
struct stream_caster<Target,std::string> {
static Target stream_cast(const std::string& s)
{
std::stringstream ss(s);
Target t;
if( (ss >> t).fail() || !(ss >> ws).eof) {
throw std::bad_cast("could not stream to target");
}
return t;
}
};
template<>
struct stream_caster<std::string,std::string> {
static const std::string& stream_cast(const std::string& s)
{
return s;
}
};
}
template< typename Target, typename Source >
inline Target stream_cast(const Source& s)
{
return detail::stream_caster<Target,Source>::stream_cast(s);
}