强制String到int函数消耗整个字符串

时间:2015-10-07 11:36:57

标签: c++ string atoi string-conversion extraction-operator

给定一个应该表示数字的字符串,我想把它放入一个转换函数中,如果整个字符串没有转换,它将提供通知。

输入:"12"

  • istringstream::operator>>输出12
  • atoi输出12
  • stoi输出12

对于输入"1X"我想要一个失败的回复,但我得到了:

  • istringstream::operator>>输出1
  • atoi输出1
  • stoi输出1

输入"X2"

  • istringstream::operator>>输出0并设置错误标志
  • atoi输出0
  • stoi抛出错误

[Live Example]

有没有办法在输入"1X"上引发错误行为?

2 个答案:

答案 0 :(得分:3)

对于给定的string str,有几种方法可以实现这一点,每种方法都有优点和缺点。我在这里写了一个实例:https://ideone.com/LO2Qnq并在下面讨论:

strtol

根据建议,here strtol的out-parameter可用于获取读取的字符数。 strtol实际上会返回long而不是int,因此返回时会发生投射。

char* size;
const int num = strtol(i.c_str(), &size, 10);

if(distance(i.c_str(), const_cast<const char*>(size)) == i.size()) {
    cout << "strtol: " << num << endl;
} else {
    cout << "strtol: error\n";
}

请注意,这使用i.c_str()来引用相同的字符串。 c_str如果您有C ++ 11,则返回指向作为字符存储的基础数组的指针,而不是临时存储:

  

c_str()data()执行相同的功能

另请注意,c_str返回的指针在strtoldistance来电之间有效,除非:

  
      
  • const的非string引用传递给任何标准库函数
  •   
  • const上调用非string成员函数,不包括operator[]at()front()back(),{{1} },begin()rbegin()end()
  •   

如果您违反其中任何一种情况,则需要制作rend()基础i的临时副本并对其进行测试。

sscanf

const char*可以使用sscanf返回读取的字符数,这可能比执行指针比较更直观。如果基数很重要,%zn可能不是一个好选择。与支持基数2 - 36的sscanfstrtol不同,stoi仅提供八进制(sscanf),十进制(%o)和十六进制({{}}的说明符。 {1}})。

%d

stoi

根据建议here %x的输出参数与size_t size; int num; if(sscanf(i.c_str(), "%d%zn", &num, &size) == 1 && size == i.size()) { cout << "sscanf: " << num << endl; } else { cout << "sscanf: error\n"; } 的{​​{1}}一样,返回读取的字符数。如果第一个非空白字符不被认为是当前基数的一个数字,那么与C ++一致,这需要stoi,并且与上面sscanf的C实现不同,会抛出invalid_argument。意味着与C实现不同,这必须检查%nstring块中的错误。

stoi

答案 1 :(得分:1)

或者,如您所述,您可以使用std::istringstream,但请检查以确保将其解析为流的末尾。假设你有一个恒定的引用,你可以做类似下面的事情

T parse(const std::string& input) {
    std::istringstream iss(input);
        T result;
        iss >> result;
        if (iss.eof() || iss.tellg() == int(input.size())) {
            return result;
        } else {
            throw std::invalid_argument("Couldn't parse entire string");
    }
}

这种方法的好处是可以解析任何超载operator>>的内容。注意:我不完全确定条件是否足够,但我的测试似乎是。由于某种原因,如果解析到最后,流将会出现失败标记。