【问题标题】:Distinguish between 0-string and non-0-string区分 0 字符串和非 0 字符串
【发布时间】:2012-09-17 00:06:27
【问题描述】:

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

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... 或使用pair 或out-variable 返回带外数据。

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

如果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 语义)。 但我更感兴趣的是“stringstream 认为0-stringnon-0-string 是什么以及如何检测差异?

【问题讨论】:

  • 无法转换为数字你的意思是一个没有数字的字符串?因为在我看来,案例 2 似乎等同于案例 4。

标签: c++ string stringstream


【解决方案1】:

你的字符串转换功能不好,应该心疼。

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 函数不知道什么是有意义的默认值。

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

【讨论】:

  • 是为了说明这个例子。谢谢你提供的例子……有没有“感觉不好”的表情
  • 重点不是 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 也视为成功,我想为空字符串添加一些特殊处理就像总是成功转换一样。

【讨论】:

  • 现在您知道转换是否良好,问题是如何使这些信息有用。您可以像某些语言那样为失败的转换抛出异常,或者您可以返回更复杂的答案,例如 std::pair&lt;int, bool&gt;(或使用枚举而不是 bool 以获得更详细的答案)。
  • 您将char* 分配给字符串文字让我感觉很糟糕。
  • @DeadMG:我讨厌看到一只小狗在痛苦中。希望现在好多了。
  • 实际上,令人难以忍受的胃痛不是来自您的回答,但也没有帮助:P
【解决方案3】:

您需要返回两位信息:一位带有转换结果的整数,以及一个表示成功与否的标志。错误情况也可以通过抛出异常来处理,但通常外部数据永远不会“异常”,解析错误应该被视为正常的控制流,而不是异常。

结果如下所示:

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&lt;int&gt;(str);,并测试是否设置了结果。


要求整个字符串匹配的替代标记提取:

std::istringstream iss(s);

return iss >> result >> std::ws && iss.get() == EOF ? result : boost::none;

【讨论】:

    【解决方案4】:

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

    1. 字符串是empty(),你返回0
    2. 转换成功,您返回 vale。
    3. 转换失败,您执行了一些操作来指示失败,例如,您抛出异常。

    【讨论】:

      【解决方案5】:

      感谢所有评论的人。 这是我的想法:

      #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
      

      【讨论】:

        猜你喜欢
        • 2021-05-21
        • 2018-05-04
        • 1970-01-01
        • 1970-01-01
        • 2017-08-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多