Определение, является ли строка двойной

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

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

Ответ 1

Вам нужна функция strtod.

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

    if(*endptr != '\0' || endptr == str)
        return false;
    return true;
}

Ответ 2

Вы можете использовать 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;
  //....
}

Ответ 3

Вам предложили альтернативы C-style и 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();

Это может быть обобщено на логический возвращаемый тест, похожий на boost 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;
}

Ответ 4

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

#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");
}

Ответ 5

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