检查 C++ 输入是否为整数的现代方法

Modern Way of checking if C++ input is integer or not

我想添加用户无法在 reg 中输入非整数值的签入我的 c++ 代码。如果他输入,则会再次提示他。我在 2011 年 (How to check if input is numeric in C++) 的堆栈溢出中看到了解决方案。现在有一些现代的或好的方法还是一样?

我尝试在 ctype.h

中使用 ifdigit()
// Example program
#include <iostream>
#include <ctype.h>
using namespace std;
int main()
{
    int x;
    cout<<"Type X";
    cin>>x;
    if(!isdigit(x))
    {
     cout<<"Type Again";
     cin>>x;
    }
}

但没用

这是我要添加检查的实际问题。

 cout << "Type Reg # of Student # " << i + 1 << endl;
 do
 {
      cin >> arr[i][j];
 } while (arr[i][j] < 999 || arr[i][j] > 9999);

其中 i 和 j 在十二月。在 for 循环中。我只想添加检查输入是否不是字符串或类似的东西。不能依赖 2011 年的答案

看看下面的例子。

所有魔法都发生在 to_num() 内部,它将处理数字前后的白色 space。

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

auto to_num(const std::string& s)
{
    std::istringstream is(s);
    int n;
    bool good = (is >> std::ws >> n) && (is >> std::ws).eof();

    return std::make_tuple(n, good);
};

int main()
{
    int n;
    bool good;

    std::cout << "Enter value: ";
    for(;;)
    {
        std::string s;
        std::getline(std::cin, s);

        std::tie(n, good) = to_num(s);
        if(good) break;

        std::cout << s << " is not an integral number" << std::endl;
        std::cout << "Try again: ";
    }
    std::cout << "You've entered: " << n << std::endl;

    return 0;
}

解释里面发生了什么to_num():

  1. (is >> std::ws >> n)is 中提取(可选)前导白色 space 和一个整数。在布尔上下文中,isoperator bool() 将启动,如果提取成功,return 为真。

  2. (is >> std::ws).eof() 提取(可选)尾随白色 space 并且如果末尾没有垃圾则 return 为真。

更新

这里是使用 c++17 中可用的 Structured binding declaration and Class template argument deduction 的稍微更简洁的版本:

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

auto to_num(const std::string& s)
{
    std::istringstream is(s);
    int n;
    bool good = (is >> std::ws >> n) && (is >> std::ws).eof();

    return std::tuple(n, good); // look ma, no make_tuple
};

int main()
{
    std::cout << "Enter value: ";
    for(;;)
    {
        std::string s;
        std::getline(std::cin, s);

        auto [n, good] = to_num(s); // structured binding
        if(good)
        {
            std::cout << "You've entered: " << n << std::endl;
            break;
        }
        else
        {
            std::cout << s << " is not an integral number" << std::endl;
            std::cout << "Try again: ";
        }
    }

    return 0;
}

如果你正确处理错误,你最终会得到一个提示/输入循环,看起来像这样:

#include <iostream>
#include <limits>

int getInput() {

    while (true) {

        std::cout << "Please enter a number between 80 and 85: ";

        int number = 0;
        std::cin >> number;

        std::cout << "\n";

        if (std::cin.eof()) {
            std::cout << "Unexpected end of file.\n";
            std::cin.clear();
            continue;
        }

        if (std::cin.bad() || std::cin.fail()) {
            std::cout << "Invalid input (error reading number).\n";
            std::cin.clear();
            std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
            continue;
        }

        if (number < 80 || number > 85) {
            std::cout << "Invalid input (number out of range).\n";
            continue;
        }

        return number;
    }

    // unreachable
    return 0;
}

int main() {

    int number = getInput();

    std::cout << number << std::endl;
}

如果不需要,我们可以省略范围检查。

我们将 std::cin.eof()(例如,用户在 Windows 上按 ctrl+Z)与其他条件分开处理,因为对于 eof 没有什么可忽略的。

这遵循空白和数字转换的标准 C++ 流行为(即,它将接受带有额外空白的输入,或仅以数值开头的输入)。

如果我们想要更好地控制我们想要接受的内容,或者不希望转换依赖于语言环境,我们必须使用 std::getlinestd::cin 读取输入,然后自己进行字符串转换(使用 std::stringstream,如 , or using std::strtol, or std::from_chars)。