Safe C ++ Way
Вы можете определить функцию для этого, используя std::istringstream
:
#include <sstream>
bool is_double(std::string const& str) {
std::istringstream ss(str);
// always keep the scope of variables as close as possible. we see
// 'd' only within the following block.
{
double d;
ss >> d;
}
/* eat up trailing whitespace if there was a double read, and ensure
* there is no character left. the eof bit is set in the case that
* `std::ws` tried to read beyond the stream. */
return (ss && (ss >> std::ws).eof());
}
Чтобы помочь вам разобраться, что он делает (некоторые пункты упрощены):
- Создание потока входных строк, инициализированного заданной строкой
- Считывание двойного значения из него с помощью
operator>>
. Это означает пропуск пробела и попытку прочитать двойное число.
- Если не может быть прочитано значение типа double, как в
abc
, поток устанавливает fail -бит. Обратите внимание, что такие случаи, как 3abc
будут успешными и не установит бит ошибки.
- Если бит сбоя установлен,
ss
оценивается как нулевое значение, что означает false .
- Если был прочитан двойной код, мы пропускаем завершающий пробел. Если мы затем окажемся в конце потока (обратите внимание, что
eof()
вернет true , если мы попытались прочитать после конца. std::ws
точно сделает это), eof
вернет true. Обратите внимание, что эта проверка гарантирует, что 3abc
не пройдет нашу проверку.
- Если оба случая, справа и слева от
&&
, оцениваются как true , мы возвращаем true для вызывающей стороны, сигнализируя, что данная строка является двойной.
Похоже, вы проверяете на int
и другие типы. Если вы знаете, как работать с шаблонами, вы знаете, как обобщить это и для других типов. Кстати, это именно то, что boost::lexical_cast
предоставляет вам. Проверьте это: http://www.boost.org/doc/libs/1_37_0/libs/conversion/lexical_cast.htm.
C Way One
Этот способ имеет преимущества (быстрота), но также и серьезные недостатки (не может быть обобщен при использовании шаблона, необходимо работать с необработанными указателями):
#include <cstdlib>
#include <cctype>
bool is_double(std::string const& s) {
char * endptr;
std::strtod(s.c_str(), &endptr);
if(endptr != s.c_str()) // skip trailing whitespace
while(std::isspace(*endptr)) endptr++;
return (endptr != s.c_str() && *endptr == '\0');
}
strtod
установит endptr
на последний обработанный символ. Что в нашем случае является завершающим нулевым символом. Если преобразование не было выполнено, для endptr устанавливается значение строки, равное strtod
.
C Way Two
Возможно, что std::sscanf
добьется цели. Но это легко что-то контролировать. Вот правильный способ сделать это:
#include <cstdio>
bool is_double(std::string const& s) {
int n;
double d;
return (std::sscanf(s.c_str(), "%lf %n", &d, &n) >= 1 &&
n == static_cast<int>(s.size()));
}
std::sscanf
вернет преобразованные предметы. Хотя в стандарте указано, что %n
не включено в этот подсчет, несколько источников противоречат друг другу. Лучше всего сравнить >=
, чтобы понять это правильно (см. Справочную страницу sscanf
). n
будет установлено на количество обработанных символов. Это сравнивается с размером строки. Пробел между двумя спецификаторами формата учитывает необязательные конечные пробелы.
Заключение
Если вы новичок, прочитайте std::stringstream
и сделайте это на языке C ++. Лучше не связывайтесь с указателями, пока не почувствуете себя хорошо с общей концепцией C ++.