给定一个应该表示数字的字符串,我想把它放入一个转换函数中,如果整个字符串没有转换,它将提供通知。
输入:"12"
:
istringstream::operator>>
输出12 atoi
输出12 stoi
输出12 对于输入"1X"
我想要一个失败的回复,但我得到了:
istringstream::operator>>
输出1 atoi
输出1 stoi
输出1 输入"X2"
:
istringstream::operator>>
输出0并设置错误标志atoi
输出0 stoi
抛出错误有没有办法在输入"1X"
上引发错误行为?
答案 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
返回的指针在strtol
和distance
来电之间有效,除非:
- 将
const
的非string
引用传递给任何标准库函数
- 在
const
上调用非string
成员函数,不包括operator[]
,at()
,front()
,back()
,{{1} },begin()
,rbegin()
和end()
如果您违反其中任何一种情况,则需要制作rend()
基础i
的临时副本并对其进行测试。
sscanf
const char*
可以使用sscanf
返回读取的字符数,这可能比执行指针比较更直观。如果基数很重要,%zn
可能不是一个好选择。与支持基数2 - 36的sscanf
和strtol
不同,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实现不同,这必须检查%n
和string
块中的错误。
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>>
的内容。注意:我不完全确定条件是否足够,但我的测试似乎是。由于某种原因,如果解析到最后,流将会出现失败标记。