Я слышал, что я должен использовать strtol
вместо atoi
из-за его лучшей обработки ошибок. Я хотел посмотреть, смогу ли я использовать этот код, чтобы проверить, является ли строка целым числом:
#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;
}
Я заменил ANYTHING
с 5
и это сработало отлично:
testString = 5
errno = 0
Success.
testInt = 5
И когда я делаю это с 2147483648
, самое большое возможное int + 1, это возвращает это:
testString = 2147483648
errno = 34
There was an error.
testInt = 2147483647
Справедливо. Но когда я попробую это с Hello world!
, это подходит:
testString = Hello world!
errno = 0
Success.
testInt = 0
Что мне здесь делать? И, пожалуйста, не давайте мне ничего сложного для чего-то такого простого, как проверка, что строка является целым числом.
Использование: GNU GCC Compiler, Code :: Blocks, Windows
«Пусть g ++ следует стандарту языка C ++ 11 ISO C ++ [-std = c ++ 11]», было проверено в «Флагах компилятора».
В соответствии с справочная страница 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 == '\0';
}
В 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
и код упрощен.
strtol останавливается на первой не цифре
но если вы читаете страницу руководства http://man7.org/linux/man-pages/man3/strtol.3.html ты можешь видеть
Если endptr не равен NULL, strtol () сохраняет адрес первого
недопустимый символ в * endptr. Если бы не было цифр вообще,
strtol () сохраняет исходное значение nptr в * endptr (и возвращает
0). В частности, если * nptr не равно «\ 0», а ** endptr равно «\ 0» в
вернуть, вся строка действительна.
т.е.
string testString = "ANYTHING";
cout << "testString = " << testString << endl;
char *endptr;
int testInt = strtol(testString.c_str(),&endptr,0);
if(**endptr)
cout << "bad input";
Не используйте решение 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 (ссылка) с пустой строкой.
Редактировать:
Если вам нужно справиться с переполнением, используйте версию исключения выше. Только если вы не можете использовать исключения, используйте это:
#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()));
}