区分0字符串和非0字符串

时间:2012-09-15 22:11:58

标签: c++ string stringstream

我们都知道如何将字符串转换为数字,即:。

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-stringnon-0-string以及如何检测差异?

5 个答案:

答案 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)

目前还不清楚您希望如何发出结果信号:如果提取功能无法进行转换,则提取功能会将流设置为错误状态。如果没有数字可以被扩展,则整数转换失败。也就是说,你似乎有三种情况:

  1. 字符串为empty(),您返回0
  2. 转换成功,您将返回该值。
  3. 转换失败,您执行某些操作以指示失败,例如,您抛出异常。

答案 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