0

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

int str2num(const string& str) 
{
   stringstream is(str);
   int result;
   return is >> result ? result : 0;
};

我的问题我希望能够区分字符串何时无法转换为数字但不是 0 例如:

1.) "0" => 0
2.) "0dasd" => 0
3.) "" => 0
4.) "some string" => 0 but true
5.) "345" => 345

我希望能够检测到案例(4)。我唯一的想法是查找字符串!! .find()或其他东西.. stringstream 是否有某种指示这种情况的方法?


编辑:一些澄清:num2str()当对话失败和/或返回时我0可以使用该功能,该功能也适用于return 0ie (cases:1,2,3,4)。但是然后在 中case 4,我希望能够在函数内部检测到它,这样就像你说的那样抛出一个err... 或使用 pair<> 或 out-variable 返回带外数据。

或者更清楚地说,我想检测:

如果is >> num returns 0 (ex:"0","0.0","000", "0sad","asd0ss")它真的是零还是字符串不能转换为数字 IE 区分 0 字符串和非 0 字符串

PS> 我的困惑可能也会出现,因为我不确定在转换时哪些情况下 0-in-a-string 会被解释为 0-num 或 just-string。我是否更加困惑:)或者现在更清楚了?我想按照 Perl 零但真实的语义来实现一些东西。


EDIT2:感谢您提供有关如何准确返回越界数据的所有示例,我非常感谢它们..我的意思是真的..(我可能会使用pair<>,不想使用boost或C++11语义)。但我更感兴趣的是“stringstream 的想法是什么0-string以及non-0-string如何检测差异?

4

5 回答 5

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 视为成功,我想为空字符串添加一些特殊处理并不需要太多,因为总是成功转换。

于 2012-09-15T22:25:21.910 回答
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 函数不知道一个有意义的默认值可能是什么。

如果用户没有以错误处理函数或有意义的默认值的形式提供明确的错误处理策略,那么抛出异常是唯一的方法。

于 2012-09-15T23:16:22.883 回答
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;
于 2012-09-15T23:23:21.973 回答
0

Thanks to all who commented. Here is what I had in mind :

#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
于 2012-09-16T07:24:37.980 回答
0

不清楚您希望如何发出结果信号:如果提取函数未能进行转换,则它们会将流设置为错误状态。如果无法提取任何数字,则整数转换将失败。也就是说,您似乎有三种情况:

  1. 字符串是empty(),你返回0
  2. 转换成功,您返回 vale。
  3. 转换失败,您做一些事情来表明失败,例如,您抛出一个异常。
于 2012-09-15T22:27:13.447 回答