Как проверить, является ли строка C ++ целым числом? - PullRequest
37 голосов
/ 16 мая 2010

Когда я использую 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;
    }
}

Ответы [ 10 ]

66 голосов
/ 17 мая 2010

Другая версия ...

Используйте 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 проанализирует строку, остановившись на первом символе, который нельзя считать частью целого числа. Если вы укажете p (как я делал выше), он установит p прямо на этот первый нецелый символ.

Я рассуждаю так: если p не установлен в конец строки (символ 0), тогда в строке есть нецелый символ s, означающий, что s не является правильным целым числом ,

Первые тесты предназначены для устранения угловых случаев (начальные пробелы, пустая строка и т. Д.).

Эта функция, конечно, должна быть настроена в соответствии с вашими потребностями (ли пробелы - ошибка? И т. Д.).

Источники:

См. Описание strtol по адресу: http://en.cppreference.com/w/cpp/string/byte/strtol.

См. Также описание родственных функций strtol (strtod, strtoul и т. Д.).

56 голосов
/ 16 июня 2016

Принятый ответ даст ложный положительный результат, если ввод представляет собой число плюс текст, потому что "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;
}
16 голосов
/ 16 мая 2010

Вы можете попробовать 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;
}
8 голосов
/ 16 мая 2010

Если вы просто проверяете, является ли word числом, это не так уж сложно:

#include <ctype.h>

...

string word;
bool isNumber = true;
for(string::const_iterator k = word.begin(); k != word.end(); ++k)
    isNumber &&= isdigit(*k);

Оптимизируйте по желанию.

4 голосов
/ 24 января 2013

Используйте всевозможные функции 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
4 голосов
/ 16 мая 2010

Вы можете использовать boost::lexical_cast, как предложено, но если у вас есть какие-либо предварительные знания о строках (то есть, если строка содержит целочисленный литерал, она не будет иметь начального пробела или что целые числа никогда не пишутся с показателями степени ), тогда выполнение собственной функции должно быть более эффективным и не особенно сложным.

3 голосов
/ 16 мая 2010

Хорошо, как я вижу, у вас есть 3 варианта.

1: Если вы просто хотите проверить, является ли число целым числом, и не хотите преобразовывать его, а просто хотите сохранить его как строку и не заботиться о возможных переполнениях, проверяя, соответствует ли регулярное выражение для целого числа было бы идеальным здесь.

2: Вы можете использовать boost :: lexical_cast, а затем перехватить потенциальное исключение boost :: bad_lexical_cast, чтобы проверить, не удалось ли преобразование. Это будет хорошо работать, если вы можете использовать повышение и если сбой преобразования является исключительным условием.

3: Сверните свою собственную функцию, подобную lexical_cast, которая проверяет конвертацию и возвращает true / false в зависимости от того, успешно это или нет. Это сработает, если 1 и 2 не соответствуют вашим требованиям.

1 голос
/ 10 июля 2017

Вот еще одно решение.

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
}
1 голос
/ 24 ноября 2015

Я изменил метод Парсебала , чтобы удовлетворить мои потребности:

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. Вы можете проверить различные базы (двоичные, октальные, шестнадцатеричные и другие)
  2. Сделайте уверенным , что вы не передаете 1, отрицательное значение или значение >36 в качестве базового.
  3. Если вы передадите 0 в качестве базы, она автоматически определит базу, то есть строка, начинающаяся с 0x, будет считаться шестнадцатеричной, а строка, начинающаяся с 0, будет считаться октой. Символы не чувствительны к регистру.
  4. Любой пробел в строке вернет false.
1 голос
/ 16 мая 2010
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");
...