Как проверить, является ли строка С++ int?
Когда я использую getline
, я бы ввел кучу строк или чисел, но я хочу, чтобы цикл while выводил "слово", если это не число.
Так есть ли способ проверить, является ли "слово" числом или нет? Я знаю, что я мог бы использовать atoi()
для
C-строки, но как насчет строк строкового класса?
int main () {
stringstream ss (stringstream::in | stringstream::out);
string word;
string str;
getline(cin,str);
ss<<str;
while(ss>>word)
{
//if( )
cout<<word<<endl;
}
}
Ответы
Ответ 1
Другая версия...
Используйте strtol
, оборачивая его внутри простой функции, чтобы скрыть ее сложность:
inline bool isInteger(const std::string & s)
{
if(s.empty() || ((!isdigit(s[0])) && (s[0] != '-') && (s[0] != '+'))) return false;
char * p;
strtol(s.c_str(), &p, 10);
return (*p == 0);
}
Почему strtol
?
Насколько я люблю C++, иногда C API является лучшим ответом, насколько я понимаю:
- использование исключений является излишним для теста, который разрешен на неудачу
- создание объекта временного потока лексическим преобразованием является чрезмерным и неэффективным, когда стандартная библиотека C имеет малоизвестную выделенную функцию, которая выполняет эту работу.
Как это работает?
strtol
первый взгляд strtol
кажется довольно сырым, поэтому объяснение сделает код более простым для чтения:
strtol
проанализирует строку, остановившись на первом strtol
который нельзя считать частью целого числа. Если вы предоставите p
(как я сделал выше), он устанавливает p
прямо на этот первый нецелый символ.
Я считаю, что если p
не установлен в конец строки (символ 0), то в строке s
есть нецелый символ, означающий, что s
не является правильным целым числом.
Первые тесты предназначены для устранения угловых случаев (начальные пробелы, пустая строка и т.д.).
Эта функция, конечно, должна быть настроена в соответствии с вашими потребностями (ли пробелы - ошибка? И т.д.).
Источники:
Смотрите описание strtol
адресу: http://en.cppreference.com/w/cpp/string/byte/strtol.
См. Также описание родственных функций strtol
(strtod
, strtoul
и т.д.).
Ответ 2
Принятый ответ даст ложный положительный результат, если ввод представляет собой число плюс текст, потому что "stol" преобразует первые цифры и игнорирует остальные.
Мне больше всего нравится следующая версия, так как это хороший однострочный текст, который не требует определения функции, и вы можете просто копировать и вставлять туда, где вам это нужно.
#include <string>
...
std::string s;
bool has_only_digits = (s.find_first_not_of( "0123456789" ) == std::string::npos);
РЕДАКТИРОВАТЬ: если вам нравится эта реализация, но вы хотите использовать ее как функцию, то это должно сделать:
bool has_only_digits(const string s){
return s.find_first_not_of( "0123456789" ) == string::npos;
}
Ответ 3
Вы можете попробовать boost::lexical_cast
. Он выдает исключение bad_lexical_cast
, если он терпит неудачу.
В вашем случае:
int number;
try
{
number = boost::lexical_cast<int>(word);
}
catch(boost::bad_lexical_cast& e)
{
std::cout << word << "isn't a number" << std::endl;
}
Ответ 4
Если вы просто проверяете, является ли word
число, это не слишком сложно:
#include <ctype.h>
...
string word;
bool isNumber = true;
for(string::const_iterator k = word.begin(); k != word.end(); ++k)
isNumber &&= isdigit(*k);
Оптимизируйте по желанию.
Ответ 5
Вы можете использовать boost::lexical_cast
, как было предложено, но если у вас есть какие-либо предварительные знания о строках (т.е. если строка содержит целочисленный литерал, у нее не будет никакого ведущего пространства или что целые числа никогда не записываются с показателями), то выполнение вашей собственной функции должно быть как более эффективным, так и не особо сложным.
Ответ 6
Используйте всемогущие функции C stdio/string:
int dummy_int;
int scan_value = std::sscanf( some_string.c_str(), "%d", &dummy_int);
if (scan_value == 0)
// does not start with integer
else
// starts with integer
Ответ 7
Хорошо, как я вижу, у вас есть 3 варианта.
1: Если вы просто хотите проверить, является ли число целым, и не заботятся о его преобразовании, но просто хотите сохранить его как строку и не заботиться о потенциальных переполнениях, проверяя, соответствует ли оно regex для целого числа будет идеальным здесь.
2: Вы можете использовать boost:: lexical_cast, а затем поймать исключение потенциального boost:: bad_lexical_cast, чтобы узнать, не произошло ли преобразование. Это будет хорошо работать, если вы можете использовать boost, и если отказ от преобразования является исключительным условием.
3: сворачивайте свою собственную функцию, аналогичную lexical_cast, которая проверяет преобразование и возвращает true/false в зависимости от того, успешна она или нет. Это будет работать в случае, если 1 и 2 не соответствуют вашим требованиям.
Ответ 8
template <typename T>
const T to(const string& sval)
{
T val;
stringstream ss;
ss << sval;
ss >> val;
if(ss.fail())
throw runtime_error((string)typeid(T).name() + " type wanted: " + sval);
return val;
}
И тогда вы можете использовать его так:
double d = to<double>("4.3");
или
int i = to<int>("4123");
Ответ 9
Я изменил метод paercebal для удовлетворения моих потребностей:
typedef std::string String;
bool isInt(const String& s, int base){
if(s.empty() || std::isspace(s[0])) return false ;
char * p ;
strtol(s.c_str(), &p, base) ;
return (*p == 0) ;
}
bool isPositiveInt(const String& s, int base){
if(s.empty() || std::isspace(s[0]) || s[0]=='-') return false ;
char * p ;
strtol(s.c_str(), &p, base) ;
return (*p == 0) ;
}
bool isNegativeInt(const String& s, int base){
if(s.empty() || std::isspace(s[0]) || s[0]!='-') return false ;
char * p ;
strtol(s.c_str(), &p, base) ;
return (*p == 0) ;
}
Примечание:
- Вы можете проверить различные базы (двоичные, октавные, шестнадцатеричные и другие)
- Сделайте уверенным, вы не передаете
1
, отрицательное значение или значение >36
в качестве базы.
- Если вы передадите
0
в качестве базы, он автоматически определит базу i.e для строки, начинающейся с 0x
, будет обрабатываться как hex, а строка, начинающаяся с 0
, будет обрабатываться как oct. Символы не чувствительны к регистру.
- Любое пустое пространство в строке приведет к возврату false.
Ответ 10
Вот еще одно решение.
try
{
(void) std::stoi(myString); //cast to void to ignore the return value
//Success! myString contained an integer
}
catch (const std::logic_error &e)
{
//Failure! myString did not contain an integer
}