Кто-нибудь знает о удобном способе определения, является ли строковое значение "квалифицируется" как число с плавающей запятой?
bool IsFloat( string MyString )
{
... etc ...
return ... // true if float; false otherwise
}
Кто-нибудь знает о удобном способе определения, является ли строковое значение "квалифицируется" как число с плавающей запятой?
bool IsFloat( string MyString )
{
... etc ...
return ... // true if float; false otherwise
}
Если вы не можете использовать библиотечную функцию Boost, вы можете написать свою собственную функцию isFloat, как это.
#include <string>
#include <sstream>
bool isFloat( string myString ) {
std::istringstream iss(myString);
float f;
iss >> noskipws >> f; // noskipws considers leading whitespace invalid
// Check the entire string was consumed and if either failbit or badbit is set
return iss.eof() && !iss.fail();
}
Вам может понравиться Boost lexical_cast (см. Http://www.boost.org/doc/libs/1_37_0/libs/conversion/lexical_cast.htm).
bool isFloat(const std::string &someString)
{
using boost::lexical_cast;
using boost::bad_lexical_cast;
try
{
boost::lexical_cast<float>(someString);
}
catch (bad_lexical_cast &)
{
return false;
}
return true;
}
Вы можете использовать istream, чтобы избежать необходимости в Boost, но, честно говоря, Boost слишком хорош, чтобы обойтись без него.
Вдохновленный этим ответом Я изменил функцию, чтобы проверить, является ли строка числом с плавающей запятой. Это не потребует повышения и не зависит от строковой последовательности - это просто анализ.
static bool isFloatNumber(const std::string& string){
std::string::const_iterator it = string.begin();
bool decimalPoint = false;
int minSize = 0;
if(string.size()>0 && (string[0] == '-' || string[0] == '+')){
it++;
minSize++;
}
while(it != string.end()){
if(*it == '.'){
if(!decimalPoint) decimalPoint = true;
else break;
}else if(!std::isdigit(*it) && ((*it!='f') || it+1 != string.end() || !decimalPoint)){
break;
}
++it;
}
return string.size()>minSize && it == string.end();
}
т.е.
1
2.
3.10000
4.2f
-5.3f
+6.2f
распознается этой функцией правильно как float.
1.0.0
2f
2.0f1
Являются примерами для недействительных поплавков. Если вы не хотите распознавать числа с плавающей запятой в формате X.XXf, просто удалите условие:
&& ((*it!='f') || it+1 != string.end() || !decimalPoint)
из строки 9. И если вы не хотите распознавать цифры без '.' как float (т.е. не "1", только "1.", "1.0", "1.0f"...), вы можете изменить последнюю строку на:
return string.size()>minSize && it == string.end() && decimalPoint;
Однако: Есть много веских причин использовать либо boost lexical_cast, либо решение с использованием строковых потоков, а не эту "уродливую функцию". Но он дает мне больше контроля над тем, какие форматы я точно хочу распознавать как числа с плавающей запятой (т.е. Максимальные цифры после десятичной точки...).
Недавно я написал функцию для проверки, является ли строка числом или нет. Это число может быть целым или с плавающей точкой.
Вы можете крутить мой код и добавить несколько юнит-тестов.
bool isNumber(string s)
{
std::size_t char_pos(0);
// skip the whilespaces
char_pos = s.find_first_not_of(' ');
if (char_pos == s.size()) return false;
// check the significand
if (s[char_pos] == '+' || s[char_pos] == '-') ++char_pos; // skip the sign if exist
int n_nm, n_pt;
for (n_nm = 0, n_pt = 0; std::isdigit(s[char_pos]) || s[char_pos] == '.'; ++char_pos) {
s[char_pos] == '.' ? ++n_pt : ++n_nm;
}
if (n_pt>1 || n_nm<1) // no more than one point, at least one digit
return false;
// skip the trailing whitespaces
while (s[char_pos] == ' ') {
++ char_pos;
}
return char_pos == s.size(); // must reach the ending 0 of the string
}
void UnitTest() {
double num = std::stod("825FB7FC8CAF4342");
string num_str = std::to_string(num);
// Not number
assert(!isNumber("1a23"));
assert(!isNumber("3.7.1"));
assert(!isNumber("825FB7FC8CAF4342"));
assert(!isNumber(" + 23.24"));
assert(!isNumber(" - 23.24"));
// Is number
assert(isNumber("123"));
assert(isNumber("3.7"));
assert(isNumber("+23.7"));
assert(isNumber(" -423.789"));
assert(isNumber(" -423.789 "));
}
Я бы предположил, что вы хотите запустить регулярное выражение во входной строке. Я думаю, что это может быть довольно сложно проверить все случаи кросс.
На этом сайте есть хорошая информация. Если вы просто хотите пропустить до конца, он говорит:
^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$
Что в принципе имеет смысл, если вы понимаете синтаксис regex.
[РЕДАКТИРОВАТЬ: Исправлено, чтобы запретить начальные пробелы и конечную глупость.]
#include <sstream>
bool isFloat(string s) {
istringstream iss(s);
float dummy;
iss >> noskipws >> dummy;
return iss && iss.eof(); // Result converted to bool
}
Вы можете легко превратить это в функцию, настроенную на тип T
вместо float
. Это по существу то, что Boost lexical_cast.
Вы можете использовать методы, описанные в Как преобразовать строку в double на С++?, и вместо того, чтобы бросать conversion_error
, верните false
(указывающий строка не представляет float
), а true
в противном случае.
Решение С++ 11 с помощью std::stof
:
bool isFloat(const std::string& s) {
try {
std::stof(s);
return true;
} catch(...) {
return false;
}
}
Я искал нечто подобное, нашел гораздо более простой ответ, чем любой, который я видел;
bool is_float(float val){
if(val != floor(val)){
return true;
}
else
return false;
}
или же:
auto lambda_isFloat = [](float val) {return (val != floor(val)); };
Надеюсь это поможет !
ZMazz
Вы можете использовать atof, а затем иметь специальную обработку для 0.0
, но я не думаю, что это считается особенно хорошее решение.
Это общий вопрос о SO. Посмотрите этот вопрос на предложения (этот вопрос обсуждает string- > int, но подходы одинаковы).
Примечание. Чтобы узнать, может ли строка быть преобразована, вам в основном нужно сделать преобразование, чтобы проверить такие вещи, как over/underflow.
Что вы можете сделать, это использовать istringstream и вернуть true/false на основе результата операции потока. Что-то вроде этого (предупреждение - я даже не скомпилировал код, это только руководство):
float potential_float_value;
std::istringstream could_be_a_float(MyString)
could_be_a_float >> potential_float_value;
return could_be_a_float.fail() ? false : true;
это зависит от уровня доверия, который вам нужен, и откуда поступают входные данные. Если данные поступают от пользователя, вы должны быть более осторожными по сравнению с импортированными данными таблицы, где вы уже знаете, что все элементы являются целыми или плавающими, и только то, что вам нужно различать.
Например, одна из самых быстрых версий, просто проверит наличие ".". и "eE" в нем. Но тогда вы можете посмотреть, все ли остальное - все цифры. Пропустить пробелы в начале - но не посередине, проверьте один ".". "eE" и т.д.
Таким образом, быстрый взлом q & d, вероятно, приведет к более сложному методу regEx-like (либо вызовите его, либо сканируйте его самостоятельно). Но тогда, как вы знаете, что результат - хотя и похожий на float - действительно может быть представлен на вашем компьютере (т.е. Попробуйте 1.2345678901234567890e1234567890). Конечно, вы можете сделать regEx с "up-to-N" цифрами в мантиссе/экспоненте, но это машина/OS/компилятор или что-то конкретное, иногда.
Итак, в конце концов, конечно, вам, вероятно, придется вызвать базовое преобразование системы и посмотреть, что вы получаете (исключение, бесконечность или NAN).
Я был бы склонен игнорировать ведущие пробелы, так как это делает функция atof
:
Функция сначала отбрасывает столько пробельные символы по мере необходимости до первого не-пробела символ найден. Затем, начиная от этого персонажа, занимает столько же символов, которые действительны следуя синтаксису, подобному синтаксису литералы с плавающей запятой и интерпретирует их как числовое значение. Остальная строка после последнего действительный символ игнорируется и не имеет влияние на поведение этого функция.
Итак, чтобы соответствовать этому, мы бы:
bool isFloat(string s)
{
istringstream iss(s);
float dummy;
iss >> skipws >> dummy;
return (iss && iss.eof() ); // Result converted to bool
}
int isFloat(char *s){
if(*s == '-' || *s == '+'){
if(!isdigit(*++s)) return 0;
}
if(!isdigit(*s)){return 0;}
while(isdigit(*s)) s++;
if(*s == '.'){
if(!isdigit(*++s)) return 0;
}
while(isdigit(*s)) s++;
if(*s == 'e' || *s == 'E'){
s++;
if(*s == '+' || *s == '-'){
s++;
if(!isdigit(*s)) return 0;
}else if(!isdigit(*s)){
return 0;
}
}
while(isdigit(*s)) s++;
if(*s == '\0') return 1;
return 0;
}
Мне всегда нравился strtof
так как он позволяет указывать конечный указатель.
bool isFloat(const std::string& str)
{
char* ptr;
strtof(str.c_str(), &ptr);
return (*ptr) == '\0';
}
Это работает, потому что указатель конца указывает на символ, где анализ начал сбой, поэтому, если он указывает на нулевой терминатор, то вся строка была проанализирована как число с плавающей точкой.
Я удивлен, что никто не упомянул этот метод за 10 лет существования этого вопроса, я полагаю, потому что это скорее способ C-стиля. Тем не менее, он все еще идеально подходит в C++ и более элегантен, чем любые потоковые решения. Кроме того, он работает с "+inf" "-inf" и т.д. И игнорирует начальные пробелы.