Это правильный подход для проверки входных данных со значениями с плавающей запятой?

Потратив достаточно много времени на изучение проверки ввода, я объединил несколько идей и придумал следующее:

Функция для проверки правильности строки double ...

bool isDouble(double& destination, string& source)
{ // 64 bit
  bool goodValue = false;

  if (!source.empty()) {
    errno = 0;
    char *garbage = nullptr;
    destination = strtod(source.c_str(), &garbage);

    if (*garbage == '\0' && errno != ERANGE)
      goodValue = true;
  }

  return goodValue;
}

Функция для проверки строки на правильность 32 бит integer ...

bool isLong(long& destination, string& source)
{ // 32 bit (base 10)
  const short BASE = 10;
  bool goodValue = false;

  if (!source.empty()) {
    errno = 0;
    char* garbage = nullptr;
    destination = strtol(source.c_str(), &garbage, BASE);

    if (*garbage == '\0' && errno != ERANGE)
      goodValue = true;
  }

  return goodValue;
}

Пример реализации

using namespace std;

int main() {
  string buffer;
  double value;

  cout << "Enter a value: ";
  getline(cin, buffer, '\n');

  if (isDouble(value, buffer))
    cout << "Value: " << value << endl;
  else
    cout << "ERROR: Invalid input\n";

  return 0;
}

Кто-нибудь может прокомментировать, если я что-то упускаю из виду при таком подходе?

4 ответа

Решение

Основываясь на отзывах тех, кто ответил, и на некоторых примерах из других вопросов, я ответил на свой вопрос. Согласно предложению FailedDev, этот вопрос должен быть помечен как ответ. Итак, вот принятый ответ.:)

Я не уверен насчет "правильного" способа, но это определенно не то, как я это сделаю. Первый и, вероятно, самый очевидный, этот кусок кода:

    for (i = 0, d = 0; i < BUFFSIZE && buffer[i] != 0 && buffer[i] >= '0' &&
             buffer[i] <= '9' || (buffer[i] == '.' && d == 0); i++)
            if (buffer[i] == '.') ++d;

дублируется в нескольких местах (по крайней мере, я думаю, что другой экземпляр идентичен, и, вероятно, должен быть в любом случае).

Во-вторых, вы не можете разрешить такие номера, как 1e23 или же -1.2, которые обычно принимаются как с плавающей запятой.

Вне руки, думаю, я бы использовал strtod попытаться преобразовать вход. Вы можете использовать его второй параметр, чтобы определить, достиг ли преобразование конца входной строки (если нет, вы будете знать, что хотя бы часть ввода не была принята). Затем вы (очевидно) захотите проверить, что возвращаемое значение было в желаемом диапазоне.

Возможно, strtod() здесь может помочь функция, так как она говорит вам, сколько было преобразовано:

const char * buf = get_raw_data(); // somehow

char * endptr;
const double value = strtod(buf, &endptr);

if (endptr != buf + std::strlen(buf))  { /* ... error ... */ }

В качестве источника для buf Вы можете маркировать свой вклад с std::string token; std::cin >> token; или что-то подобное и использовать token.c_str(),

Если это упражнение, которое вы хотите, это понятно. Но в противном случае вы можете использовать istringstream чтобы не изобретать велосипед:

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

using namespace std;

int main () {

  int n,val;
  string stringvalues;

  stringvalues = "3.14159254 f01fhasfljk";
  istringstream iss(stringvalues);

  float x,y;
  iss >> x;

  cout << x * 2 << endl;

  iss >> y;
  if ( ! iss.fail() )
    {
      cout << y * 2 << endl;
    }
  else
    {
      cout << "second value not a number..." << endl;
    }

  return 0;
}
Другие вопросы по тегам