C++:使用 "strtol" 检查字符串是否为有效整数
C++: check if string is a valid integer using "strtol"
我听说我应该使用 strtol
而不是 atoi
,因为它可以更好地处理错误。我想通过查看是否可以使用此代码检查字符串是否为整数来测试 strtol
:
#include <iostream>
#include <stdlib.h>
using namespace std;
int main()
{
string testString = "ANYTHING";
cout << "testString = " << testString << endl;
int testInt = strtol(testString.c_str(),NULL,0);
cout << "errno = " << errno << endl;
if (errno > 0)
{
cout << "There was an error." << endl;
cout << "testInt = " << testInt << endl;
}
else
{
cout << "Success." << endl;
cout << "testInt = " << testInt << endl;
}
return 0;
}
我用 5
替换了 ANYTHING
并且效果很好:
testString = 5
errno = 0
Success.
testInt = 5
当我使用 2147483648
时,最大可能的 int
+ 1 (2147483648),它 returns 这个:
testString = 2147483648
errno = 34
There was an error.
testInt = 2147483647
很公平。但是,当我尝试使用 Hello world!
时,它错误地认为它是有效的 int
和 returns 0
:
testString = Hello world!
errno = 0
Success.
testInt = 0
备注:
- 我在 Windows
上使用 Code::Blocks 和 GNU GCC 编译器
- "Have g++ follow the C++11 ISO C++ language standard [-std=c++11]" 已签入 "Compiler Flags".
strtol 在第一个非数字处停止
但是如果你阅读手册页 http://man7.org/linux/man-pages/man3/strtol.3.html 你可以看到
If endptr is not NULL, strtol() stores the address of the first
invalid character in *endptr. If there were no digits at all,
strtol() stores the original value of nptr in *endptr (and returns
0). In particular, if *nptr is not '[=11=]' but **endptr is '[=11=]' on
return, the entire string is valid.
即
string testString = "ANYTHING";
cout << "testString = " << testString << endl;
char *endptr;
int testInt = strtol(testString.c_str(),&endptr,0);
if(**endptr)
cout << "bad input";
根据the man page of strtol
。您必须定义您的函数,例如:
bool isNumeric(const std::string& str) {
char *end;
long val = std::strtol(str.c_str(), &end, 10);
if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) || (errno != 0 && val == 0)) {
// if the converted value would fall out of the range of the result type.
return false;
}
if (end == str) {
// No digits were found.
return false;
}
// check if the string was fully processed.
return *end == '[=10=]';
}
在C++11中,我比较喜欢用std::stol
而不是std::strtol
,比如:
bool isNumeric(const std::string& str) {
try {
size_t sz;
std::stol(str, &sz);
return sz == str.size();
} catch (const std::invalid_argument&) {
// if no conversion could be performed.
return false;
} catch (const std::out_of_range&) {
// if the converted value would fall out of the range of the result type.
return false;
}
}
std::stol
调用 std::strtol
,但您直接使用 std::string
并简化了代码。
不要使用带有异常的C++11方式解决方案,因为它比较慢。这是一个快速的 C++11 版本:
#include <algorithm>
bool is_decimal(const std::string& s)
{
return !s.empty() && std::find_if(s.begin(), s.end(), [](char c){ return !std::isdigit(c); }) == s.end();
}
如果您确定您的字符串大部分不为空,那么您可以删除!s.empty()。如果不是,请保留它,因为 !s.empty() (!(s.length()==0) ) 比用空字符串调用 find_if (reference) 便宜。
编辑:
如果您必须处理溢出,请使用上面的异常版本。只有当你不能使用例外时才使用这个:
#include <string>
#include <sstream>
#include <limits>
template <class T>
bool is_decimal_and_fit(const std::string& s)
{
long double decimal = 0;
return (!(std::istringstream(s) >> decimal).fail() && (decimal >= std::numeric_limits<T>::lowest()) && (decimal <= std::numeric_limits<T>::max()));
}
我听说我应该使用 strtol
而不是 atoi
,因为它可以更好地处理错误。我想通过查看是否可以使用此代码检查字符串是否为整数来测试 strtol
:
#include <iostream>
#include <stdlib.h>
using namespace std;
int main()
{
string testString = "ANYTHING";
cout << "testString = " << testString << endl;
int testInt = strtol(testString.c_str(),NULL,0);
cout << "errno = " << errno << endl;
if (errno > 0)
{
cout << "There was an error." << endl;
cout << "testInt = " << testInt << endl;
}
else
{
cout << "Success." << endl;
cout << "testInt = " << testInt << endl;
}
return 0;
}
我用 5
替换了 ANYTHING
并且效果很好:
testString = 5
errno = 0
Success.
testInt = 5
当我使用 2147483648
时,最大可能的 int
+ 1 (2147483648),它 returns 这个:
testString = 2147483648
errno = 34
There was an error.
testInt = 2147483647
很公平。但是,当我尝试使用 Hello world!
时,它错误地认为它是有效的 int
和 returns 0
:
testString = Hello world!
errno = 0
Success.
testInt = 0
备注:
- 我在 Windows 上使用 Code::Blocks 和 GNU GCC 编译器
- "Have g++ follow the C++11 ISO C++ language standard [-std=c++11]" 已签入 "Compiler Flags".
strtol 在第一个非数字处停止
但是如果你阅读手册页 http://man7.org/linux/man-pages/man3/strtol.3.html 你可以看到
If endptr is not NULL, strtol() stores the address of the first invalid character in *endptr. If there were no digits at all, strtol() stores the original value of nptr in *endptr (and returns 0). In particular, if *nptr is not '[=11=]' but **endptr is '[=11=]' on return, the entire string is valid.
即
string testString = "ANYTHING";
cout << "testString = " << testString << endl;
char *endptr;
int testInt = strtol(testString.c_str(),&endptr,0);
if(**endptr)
cout << "bad input";
根据the man page of strtol
。您必须定义您的函数,例如:
bool isNumeric(const std::string& str) {
char *end;
long val = std::strtol(str.c_str(), &end, 10);
if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) || (errno != 0 && val == 0)) {
// if the converted value would fall out of the range of the result type.
return false;
}
if (end == str) {
// No digits were found.
return false;
}
// check if the string was fully processed.
return *end == '[=10=]';
}
在C++11中,我比较喜欢用std::stol
而不是std::strtol
,比如:
bool isNumeric(const std::string& str) {
try {
size_t sz;
std::stol(str, &sz);
return sz == str.size();
} catch (const std::invalid_argument&) {
// if no conversion could be performed.
return false;
} catch (const std::out_of_range&) {
// if the converted value would fall out of the range of the result type.
return false;
}
}
std::stol
调用 std::strtol
,但您直接使用 std::string
并简化了代码。
不要使用带有异常的C++11方式解决方案,因为它比较慢。这是一个快速的 C++11 版本:
#include <algorithm>
bool is_decimal(const std::string& s)
{
return !s.empty() && std::find_if(s.begin(), s.end(), [](char c){ return !std::isdigit(c); }) == s.end();
}
如果您确定您的字符串大部分不为空,那么您可以删除!s.empty()。如果不是,请保留它,因为 !s.empty() (!(s.length()==0) ) 比用空字符串调用 find_if (reference) 便宜。
编辑: 如果您必须处理溢出,请使用上面的异常版本。只有当你不能使用例外时才使用这个:
#include <string>
#include <sstream>
#include <limits>
template <class T>
bool is_decimal_and_fit(const std::string& s)
{
long double decimal = 0;
return (!(std::istringstream(s) >> decimal).fail() && (decimal >= std::numeric_limits<T>::lowest()) && (decimal <= std::numeric_limits<T>::max()));
}