整数输入验证 - 拒绝非整数输入并在 C++ 中请求另一个输入?

Integer input validation - Rejecting non integer input and requesting another in C++?

当 valid_office_num 为 false 时,此函数不断在 while 循环内的另一个函数中调用。问题是,如果输入以数字开头但后面跟着其他无效字符(例如 5t),它会采用数字部分并将其接受为有效输入。我希望它考虑整个输入并拒绝它,以便它可以请求另一个。我以为我可以使用 getline() 但后来我不能使用 cin.fail()。我该如何实现这种行为?

我忘了说我是 C++ 的新手,到目前为止我只学了基础知识。

(需要明确的是,期望的行为是拒绝任何包含数字以外的任何内容。这不是整数范围检查问题。如果它不是整数,请丢弃它并请求另一个)

//Function to read a valid office number, entered by user
int read_office_num()
{
    //Declaration of a local variable
    int office_num;

    //Read input
    cin >> office_num;

    //Check if input was valid
    if (cin.fail())
    {
        //Print error message
        cout << "\nInvalid office number, it should only consist of digits!! Enter another:\n";
        //Clear error flags
        cin.clear();
        //Ignore any whitespace left on input stream by cin
        cin.ignore(256, '\n');
    }
    else
    {
        //Office number entered is valid
        valid_office_num = true;
    }

    return office_num;
}

嗯。我可能遗漏了一些东西,但为什么不读一行,trim 它,使用正则表达式来验证一个数字,然后利用 strstream 的设施或者如果必须的话只利用 atoi?在所有现实中,我可能只是让用户摆脱无关的输入(但如果我确定我总是以交互方式 运行ning 则丢弃它)。遵循座右铭 "be lenient in what you accept."

"interactive" 警告很重要。人们通常不能假设 cin 是终端。有人可能会变得自大,让您的程序 运行 在文本文件或管道中运行,然后它就会失败。一种稳健的方法会将数据处理(便携式)与输入方式(可能是特定于机器的,因此也比通过控制台 stdin/stdout 更强大和有用)分开。

您可以使用 stringstream

int read_office_num()
{
    //Declaration of a local variable
    int office_num;

    string input = "";

    while (true) {
        getline(cin, input);
        stringstream myStream(input);
        if (myStream >> office_num)
            break;
        cout << "\nInvalid office number, it should only consist of digits!! Enter another:\n" << endl;
    }

    return office_num;
}

如果你想拒绝像 123 xxx 这样的输入,你可以添加一个额外的检查来验证接收到的字符串确实是一个整数:

bool is_number(const string& s)
{
    string::const_iterator itr = s.begin();
    while (itr != s.end() && isdigit(*itr)) ++itr;
    return !s.empty() && itr == s.end();
}

int read_office_num()
{
    //Declaration of a local variable
    int office_num;

    string input = "";

    while (true) {
        getline(cin, input);
        stringstream myStream(input);
        if (is_number(input) && myStream >> office_num)
            break;
        cout << "\nInvalid office number, it should only consist of digits!! Enter another:\n" << endl;
    }

    return office_num;
}

据我了解,您希望将整行作为数字读取,否则会失败?

嗯,你可以使用std::getline(),但你必须遵循下面的算法(我会把实现留给你..)

  1. 使用std::getline(cin, str)读取一行,如果return为真
  2. 使用std::stoi(str, &pos)转换为整数并获取最后一个整数的位置
  3. 如果 pos != str.size() 则整行不是整数(或者如果上面抛出异常),则它不是有效整数,否则 return 值...

使用 std::getline().

将一行输入读取为 std::string

检查字符串并检查它是否包含任何非数字字符。

如果字符串只包含数字,使用std::istringstream从字符串中读取一个整数。否则报告失败,或采取任何其他需要的恢复操作(例如丢弃整个字符串并 return 读取另一个)。

您可能应该只查看 cin 中剩余的输入字符数。你可以用 in_avail

你的函数最终可能会有一个像这样的主体:

//Declaration of a local variable
int office_num;

//Read input and check if input was valid
for (cin >> office_num; cin.rdbuf()->in_avail() > 1; cin >> office_num){
    //Print error message
    cout << "\nInvalid office number, it should only consist of digits!! Enter another:\n";
    //Ignore any whitespace left on input stream by cin
    cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}

//Office number entered is valid
valid_office_num = true;

return office_num;

兴趣点:

  1. cin 中始终至少有 1 个字符,否则 cin 将被标记为 bad,这样就不好了
  2. 如果 read_office_num 以这种方式实现,则不需要 valid_office_num,因为 valid_office_num 在返回
  3. 之前将始终设置为 true

使用 Boost Lexical Cast 的方法如下:

#include <boost/lexical_cast.hpp>
#include <iostream>
#include <vector>
#include <string>

int read_office_num()
{
    using boost::lexical_cast;
    using boost::bad_lexical_cast;
    using namespace std;

    int office_num;
    while (true)
    {
        try
        {
            string input = cin.getline();
            office_num = lexical_cast<int>(*argv));
            break;
        }
        catch(const& bad_lexical_cast)
        {
            cout << "\nInvalid office number, it should only consist of digits!! Enter another:\n";
        }
    }

    return office_num;
}