Когда я использую getline
, Я ввел бы набор строк или чисел, но я только хочу, чтобы цикл с условием продолжения произвел "слово", если это не число. Так есть ли какой-либо способ проверить, является ли "слово" числом или нет? Я знаю, что мог использовать atoi()
для струн до, но как насчет для строк строкового класса?
int main () {
stringstream ss (stringstream::in | stringstream::out);
string word;
string str;
getline(cin,str);
ss<<str;
while(ss>>word)
{
//if( )
cout<<word<<endl;
}
}
Другая версия...
Используйте 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++, иногда API C является лучшим ответом, насколько я понимаю:
strtol
на первый взгляд кажется довольно грубым, поэтому объяснение упростит чтение кода:
strtol
разберет строку, остановившись на первом символе, который нельзя считать частью целого числа. Если указать p
(как я сделал выше), он установит p
прямо на этот первый нецелый символ.
Я рассуждаю так: если p
не установлен в конец строки (символ 0), то в строке s
есть нецелый символ, а значит s
не является правильным целым числом.
Первые тесты служат для исключения угловых случаев (пробелы, пустая строка и т.д.).
Разумеется, эта функция должна быть адаптирована под ваши нужды (являются ли пробелы ошибкой? и т.д.).
См. описание strtol
на: http://en.cppreference.com/w/cpp/string/byte/strtol.
См. также описание родственных функций strtol
(strtod
, strtoul
и т.д.).
Если вы просто проверяете, слово
- это число, это не слишком сложно:
#include <ctype.h>
...
string word;
bool isNumber = true;
for(string::const_iterator k = word.begin(); k != word.end(); ++k)
isNumber &&= isdigit(*k);
Оптимизируйте по желанию.
Вы можете попробовать 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;
}
Вы можете использовать boost :: lexical_cast
, как предлагается, но если у вас есть какие-либо предварительные знания о строках (т. Е. Если string содержит целочисленный литерал, у которого не будет начального пробела или что целые числа никогда не записываются с показателями), то прокрутка вашей собственной функции должна быть более эффективной и не особенно сложной.
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");
Итак, как я понимаю, у вас есть 3 варианта.
1: Если вы просто хотите проверить, является ли число целым, и не заботитесь о его преобразовании, а просто хотите сохранить его как строку и не заботитесь о потенциальных переполнениях, то проверка соответствия regex для целого числа будет идеальным вариантом.
2: Вы можете использовать boost::lexical_cast и затем поймать потенциальное исключение boost::bad_lexical_cast, чтобы узнать, не произошло ли преобразование. Это будет хорошо работать, если вы можете использовать boost и если неудача преобразования является исключительным условием.
3: Создайте собственную функцию, аналогичную lexical_cast, которая проверяет преобразование и возвращает true/false в зависимости от того, успешно оно или нет. Это будет работать в случае, если 1 и 2 не подходят под ваши требования.