我们都知道如何将字符串转换为数字,即:。
int str2num(const string& str)
{
stringstream is(str);
int result;
return is >> result ? result : 0;
};
我的问题我希望能够区分字符串何时无法转换为数字但不是0 ex。:
1.) "0" => 0
2.) "0dasd" => 0
3.) "" => 0
4.) "some string" => 0 but true
5.) "345" => 345
我希望能够检测到案例(4)。
我唯一的想法是查找字符串!! .find()
或其他东西..
stringstream是否有某种方式来表明这种情况?
编辑:一些澄清:
作为num2str()
函数,当对话失败和/或返回0
时我就可以了,该函数也可以return 0
,即(cases:1,2,3,4)
。
但是在case 4
中,我希望能够在函数内部检测它,这样就像你说的那样抛出一个err
...或者使用对<>返回带外数据。或者变量。
或者更清楚我想要发现:
如果is >> num returns 0 (ex:"0","0.0","000", "0sad","asd0ss")
它真的是零或者它是字符串,那么不可转换为数字I.E.区分0字符串和非0字符串
PS> 我的混淆可能也会出现,因为我不确定在转换时哪个0-in-a-string的情况被解释为0-num或just-string。 我更混淆了:)还是现在更清楚了? 我想按照Perl零但真实的语义来实现某些东西。
EDIT2:感谢所有关于如何准确返回越界数据的例子,我真的很感激他们......我的意思是真的......
(我可能会使用pair<>,不想使用boost或C++11
语义。
但我更感兴趣的是“什么字符串流认为0-string
和non-0-string
以及如何检测差异?
答案 0 :(得分:2)
测试您是否成功转换了某些内容非常容易。区分你的第三和第四种情况会变得有点困难 - 将“没有输入转换”视为“成功转换某些东西”似乎(对我而言)没有多大意义。如果你可以将案例3和4视为不成功的转换,其余的就是成功,那么这很简单:只需在尝试转换后测试流的状态:
#include <sstream>
#include <string>
#include <iostream>
int main(){
char const *inputs[] = { "0", "0dasd", "", "some string", "345"};
for (int i=0; i<5; i++) {
std::istringstream buf(inputs[i]);
int val;
if (buf>>val)
std::cout << "Converted : \"" << inputs[i] << "\" To: " << val << "\n";
else
std::cout << "Could not convert: \"" << inputs[i] << "\" To int\n";
}
return 0;
}
产生:
Converted : "0" To: 0
Converted : "0dasd" To: 0
Could not convert: "" To int
Could not convert: "some string" To int
Converted : "345" To: 345
如果你真的想要将案例3视为成功,我想对于空字符串添加一些特殊处理并不会花费很多,因为总是成功转换。
答案 1 :(得分:2)
你的字符串转换功能不好,你应该心疼。
template<typename F> int str2num(const string& str, F&& f) {
stringstream is(str);
int result;
if (is >> result) return result;
return f();
}
int str2num(const string& str) {
return str2num(str, [] -> int {
throw std::runtime_error("Parse failure!");
});
}
int str2num(const string& str, int def) {
return str2num(str, [=] {
return def;
});
}
你选择0作为一个神奇的默认值是坏的 - 对于想要尝试解析整数的人来说,32是一个理智的默认值。 0也可以是与解析失败分开的有意义的值。如果你想要一个默认值,你需要用户明确指定这个,因为你的随机I / O函数不知道有什么有意义的默认值。
如果用户没有提供明确的错误处理策略,无论是以错误处理函数还是有意义的默认值的形式,那么抛出异常是唯一的方法。
答案 2 :(得分:1)
您需要返回两位信息:一个包含转换结果的整数,以及一个表示成功或否则的标志。错误条件也可以通过抛出异常来处理,但通常外部数据永远不会“异常”,解析错误应该被视为正常的控制流,而不是例外。
结果看起来像这样:
template <typename T>
boost::optional<int> parse_as(std::string const & s)
{
if (s.empty()) { return T(); }
T result;
return std::istringstream(s) >> result ? result : boost::none;
}
用法:auto n = parse_as<int>(str);
,并测试结果是否已设置。
需要整个字符串匹配的备用标记提取:
std::istringstream iss(s);
return iss >> result >> std::ws && iss.get() == EOF ? result : boost::none;
答案 3 :(得分:0)
目前还不清楚您希望如何发出结果信号:如果提取功能无法进行转换,则提取功能会将流设置为错误状态。如果没有数字可以被扩展,则整数转换失败。也就是说,你似乎有三种情况:
empty()
,您返回0
。答案 4 :(得分:0)
感谢所有评论的人。 这就是我的想法:
#include <iostream>
#include <string>
#include <sstream>
#include <assert.h>
using namespace std;
#define pBool std::pair<bool,int>
pBool str2num(const string& str) {
istringstream is(str);
pBool rv(false,0);
if (str == "0E0") {//Zero but true
rv = std::make_pair(true,0);
} else {
is >> rv.second;//convert
//cout << "fail?:" << is.fail() << endl;
//logical XOR : !fail != !0?
if ( !is.fail() != (rv.second == 0) ) rv.first = true;
// if (!is.fail() && rv.second != 0) rv.first = true;//successful conversion
// if (is.fail() && rv.second == 0) rv.first = true;
};
return rv;
};
template<class T>
void dump_pair(T& p) {
cout << "Bool:" << p.first << endl;
cout << "Val :" << p.second << endl;
}
int main() {
cout << ">>0E0" << endl;
pBool rv1 = str2num("0E0");
dump_pair(rv1);
cout << ">>0" << endl;
pBool rv2 = str2num("0");
dump_pair(rv2);
cout << ">>0.0dsad" << endl;
pBool rv3 = str2num("0dsad");
dump_pair(rv3);
cout << ">>456ttt" << endl;
pBool rv4 = str2num("456ttt");
dump_pair(rv4);
cout << ">>adttt" << endl;
pBool rv5 = str2num("ad555ttt");
dump_pair(rv5);
return 0;
}
====OUTPUT====
>>0E0
Bool:1
Val :0
>>0
Bool:0
Val :0
>>0.0dsad
Bool:0
Val :0
>>456ttt
Bool:1
Val :456
>>adttt
Bool:1
Val :0