Определение, является ли строка двойной - PullRequest
10 голосов
/ 09 мая 2011

Я хотел бы посмотреть, содержит ли строка double в качестве единственного содержимого.Другими словами, если это может быть выводом следующей функции:

string doubleToString(double num)
{
    stringstream s;
    s << num;
    return s.str();
}

Ответы [ 5 ]

11 голосов
/ 09 мая 2011

Требуется функция strtod .

bool isOnlyDouble(const char* str)
{
    char* endptr = 0;
    strtod(str, &endptr);

    if(*endptr != '\0' || endptr == str)
        return false;
    return true;
}
6 голосов
/ 09 мая 2011

Вы можете использовать Boost lexical_cast, чтобы проверить, содержит ли строка double или нет.

#include <boost/lexical_cast.hpp> 
....
using boost::lexical_cast; 
using boost::bad_lexical_cast; 
....
template<typename T> bool isValid(const string& num) { 
   bool flag = true; 
   try { 
      T tmp = lexical_cast<T>(num); 
   } 
   catch (bad_lexical_cast &e) { 
      flag = false; 
   } 
   return flag; 
} 

int main(){
  // ....
 if (isValid<double>(str))
     cout << "valid double." << endl; 
 else 
     cout << "NOT a valid double." << endl;
  //....
}
5 голосов
/ 09 мая 2011

Вам предложили варианты в стиле C и Boost, но в стиле вашей doubleToString реализации:

bool is_double(const std::string& s)
{
    std::istringstream iss(s);
    double d;
    return iss >> d >> std::ws && iss.eof();
}

Здесь вы проверяете, iss >> d возвращает iss, который оценивается как true только в логическом контексте, если потоковая передача прошла успешно. Проверка на наличие только пробелов перед eof() гарантирует отсутствие завершающего мусора.

Если вы также хотите рассмотреть начальный и конечный пробельные символы:

    return iss >> std::nowkipws >> d && iss.eof();

Это можно обобщить в булево-возвращающий тест, похожий на буст lexical_cast<> ...

template <typename T>
bool is_ws(const std::string& s)
{
    std::istringstream iss(s);
    T x;
    return iss >> x >> std::ws && iss.eof();
}

template <typename T>
bool is(const std::string& s)
{
    std::istringstream iss(s);
    T x;
    return iss >> std::noskipws >> x && iss.eof();
}

...
if (is<double>("3.14E0")) ...
if (is<std::string>("hello world")) ...; // note: NOT a single string
                                         // as streaming tokenises at
                                         // whitespace by default...

Вы можете специализировать шаблон для любых типов поведения, которые вам нравятся, например:

template <>
bool is<std::string>(const std::string& s)
{
    return true;
}
2 голосов
/ 09 мая 2011

Или используйте потоки напрямую:

#include <string>
#include <sstream>
#include <iostream>

template<typename T>
bool isValid(std::string const& num)
{
    T  value;
    std::stringstream stream(num);
    stream >> value;

    // If the stream is already in the error state peak will not change it.
    // Otherwise stream should be good and there should be no more data
    // thus resulting in a peek returning an EOF
    return (stream) &&
           stream.peek() == std::char_traits<typename std::stringstream::char_type>::eof();
}

int main()
{
    isValid<double>("55");
}
0 голосов
/ 09 мая 2011

Поскольку никто больше не упоминал об этом: очевидное решение заключается в том, что вы хотите знать, имеет ли строка заданный синтаксис, - использовать регулярные выражения.Я не уверен, что это лучшее решение в этом случае, поскольку регулярное выражение для легального double довольно сложно (и, следовательно, легко ошибиться).И ваша спецификация несколько расплывчата: вы хотите принять любую строку, которая может быть проанализирована (например, >>), как допустимый double, или только ваша строка может быть возвращена вашей doubleToString функцией?Если первое, самое простое решение, вероятно, состоит в том, чтобы преобразовать строку в двойное число, убедившись, что ошибки нет, и вы использовали все символы (решение Мартина, за исключением того, что глупо делать его шаблоном, пока вам это не нужно),Если последнее, самое простое решение состоит в том, чтобы преобразовать двойник, который вы нашли, обратно в строку, используя вашу функцию, и сравнить две строки.(Просто чтобы прояснить разницу: функция Мартина вернет true для таких вещей, как "&nbsp;&nbsp;1.0", "1E2", ".00000000001" и "3.14159265358979323846264338327950288419716939937", которые ваша функция никогда не сгенерирует.)

...