C++ How to check an input float variable for valid

2020-08-01 07:18发布

问题:

I'm writing a program that acts as a calculator; based on the character input by the user it performs a certain operation. The structure of the program seems to work fine, but I'd like to be able to check for erroneous input. After receiving the float variable, is there any way to check if it does not contain any characters other than digits and decimals? I've tried isdigit, and this:

if (!(cin >> x)) {
    cout << "You did not enter a correct number!" << endl; 
    return;
}

But nothing seems to be working.

Here is a sample of one of the simple operation functions I'm using:

void Add(){
    float x = 0, y = 0, z = 0;
    cout << "Please enter two numbers you wish "
         << "to add separated by a white space:" << endl; 
    cin >> x >> y;
    z = x+y;
    cout << x << " + " << y << " = " << z << "." << endl;
    return;
}

回答1:

To detect erroneous string input where you expected a number, C++ doesn't automatically know what you want, so one solution is to first accept your input as strings, validate those strings, then if valid, only then convert the strings to float numbers using the atof() function.

The standard string class has a function called find_first_not_of() to help you tell C++ which characters you consider valid. If the function finds a character not in your list, it will return the position of the bad character, otherwise string::npos is returned.

// add.cpp

#include <iostream>
#include <string>
#include <cstdlib>    // for atof()

using namespace std;


void Add()
{
    cout << "Please enter two numbers you wish "
         << "to add, separated by a white space:"
         << endl;

    string num1, num2;

    cin >> num1;
    if( num1.find_first_not_of("1234567890.-") != string::npos )
    {
        cout << "invalid number: " << num1 << endl;
        return;
    }

    cin >> num2;
    if( num2.find_first_not_of("1234567890.-") != string::npos )
    {
        cout << "invalid number: " << num2 << endl;
        return;
    }

    float x = 0, y = 0, z = 0;
    x = atof( num1.c_str() );
    y = atof( num2.c_str() );
    z = x+y;

    cout << x << " + " << y << " = " << z << "." << endl;
}

int main(void)
{
    Add();
    return 0;
}


回答2:

You test the state of the stream:

float x, y;
if (std::cin >> x >> y) {
    // input extraction succeeded
}
else {
    // input extraction failed
}

If this isn't working for you, then you need to post the exact code that isn't working.



回答3:

One possibility would be to read the input as a string, then use boost lexical_cast to convert to floating point. lexical_cast only considers the conversion successful if the entire input converts to the target -- otherwise, it'll throw a bad_lexical_cast exception.



回答4:

Another idea would be to test the input against a regex. An example regex for a float could be

-?[0-9]+([.][0-9]+)?

This method would also make it easier to refine the matching mechanism by only modifying the regex, and you could map multiple regular expressions against different types of input, for example an integer could then be expressed as

-?[0-9]+

and so on. Keep in mind however, that this only tests if the input is a valid format, it still requires a numerical conversion afterwards (I prefer boost::lexical_cast).

(You can also try it out with http://gskinner.com/RegExr/)