C++ 如何验证与重载 >> 运算符一起使用的输入

标签 c++ validation input operators istream

我正在编写一个可以对复数进行运算的程序。我有一个名为 ComplexNumber 的类,其中包含重载的运算符。我的程序以 complex *operator* complex 的形式从文件中获取输入。因此,例如输入看起来像 3+4i + 2+3i。我已经写了我的 >> 运营商,所以这工作正常。

当输入看起来像 3i + 1+2i 时,问题就出现了。我们必须验证输入,以便在复数缺失部分时它能正常工作。它可以只是一个实数,也可以只是一个虚数。

ComplexNumber类中与该问题相关的函数如下:

ComplexNumber::ComplexNumber(double r,double i)
{
    realNum = r;
    imaginaryNum = i;
}


istream& operator>>(istream &input , ComplexNumber& other)  //Overloaded >> operator
{
    char filter = 0;
    double r =0;
    double i = 0;

    input >> r >> i >> filter;
    other.setR(r);
    other.setI(i);

    return input;
}

我在主类中阅读输入的方式如下:

 void input(ifstream &in)
{
        ComplexNumber a,b;
        in >> a;
        in.get();
        string op;
        getline(in,op,' ');
        in >> b;
        cout << a << " " << op << " " << b << endl;
}


int main()
{
    ifstream in("complex.txt");
    if(!in) cout << "failed to open file." << endl;

    while(!in.eof()){
        input(in);
    }
    return 0;
}

为了让我的运算符工作,我需要在对象中将输入的缺失部分设置为 0。因此,如果输入是 3i,则对象中的变量将是 realNum = 0, imaginaryNum = 3 我该如何实现?

如何检查行中的输入以决定应如何读入?目前,它期望复数同时具有实部和虚部。

我还为复数只有一个部分的情况编写了一个重载构造函数,但我不确定如何使用它。函数如下:

ComplexNumber::ComplexNumber(double in, string r_i)    //Overloaded constructor
{
    if(r_i == "r"){realNum = in; imaginaryNum = 0;}
    else{imaginaryNum = in; realNum = 0;}
}

除了这个问题,我们还必须检查以确保输入没有无效字符,例如。 j 或 ! 但我觉得如果我在第一个问题上得到帮助,我可以使用提供的信息来解决第二个问题。

我意识到这可能不是最好的措辞,我只是希望你能理解我正在努力实现的目标。我真的很感激任何帮助。谢谢。

最佳答案

通常我会使用状态机来执行此操作。以前从未用 C++ 流做过。比看起来更偷偷摸摸,但基本相同。评论嵌入代码中的内容和原因。

#include <string>
#include <iostream>
#include <sstream>
#include <cmath>
#include <cctype>

// Made this really dumb for ease of writing example
struct ComplexNumber
{
    double realNum;
    double imaginaryNum;

};

// splitting the guts of the parsing off into its own function made writing
// operator>> dead easy

bool parsecomplex(std::istream &input,
                  double & real,
                  double & imag)
{
    char filter;
    double temp;
    char next;
    if (input >> temp)// read a double. No clue if it's the real or imaginary part yet.
    {
        next = input.peek(); // check the next character, but do not extract
        if (next != 'i') // not imaginary
        {
            real = temp; // store as real
            if (next == '+' || next == '-') // do we stop here or is there an imaginary?
            {
                if (input >> imag >> filter // read imaginary  
                        && filter == 'i') // and ensure trailing i
                {
                    return true;
                }
            }
            else
            {
                return true;
            }
        }
        else
        { // just an imaginary
            imag = temp;
            input >> filter; // remove the i. we already know it's an i
            return true;
        }
    }
    return false;
}

std::istream& operator>>(std::istream &input,
                         ComplexNumber& other)
{
    double real = 0.0;
    double imag = 0.0;

    if (parsecomplex(input, real, imag))
    { // OK so we got a good complex number.

        other.realNum = real;
        other.imaginaryNum = imag;
        input.clear(); // may have read eof
        return input;

      /* This next bit is a deviation from normal stream parsing. Typically 3j
         would be read and store of 3 as real and j stays in the stream for the
         next read. OP sounds like they might need to be a bit more anal. If so, 
         replace the above with 

        char next = input.peek();
        if (std::isspace(next) || next == std::char_traits<char>::eof())
        {
            other.realNum = real;
            other.imaginaryNum = imag;
            input.clear(); // may have read eof
            return input;
        }

       The Law of Least Surprise says you should go with the expected parsing 
       behaviour so as to not leave a trail of confused and angry programmers 
       in your wake. */
    }
    input.setstate(std::ios::failbit);
    return input;
}

// quick test harness
void test(const char * str)
{
    ComplexNumber cnum;
    std::stringstream input(str);

    if (input >> cnum)
    {
        std::string remaining;
        std::getline(input, remaining);
        std::cout << str << " is " << cnum.realNum <<","<< cnum.imaginaryNum
                  << " still in stream: " << remaining << std::endl;
    }
    else
    {
        std::cout << "Invalid: " << str << std::endl;
    }
}

int main()
{
    test("3-3i");
    test("3");
    test("-3i");
    test(" 3-3i");
    test("3-3i ");
    test("3 ");
    test("-3i ");
    test("3-3i 3-3i");
    test("3 -3i");
    test("j3+3i");
    test("3j3i");
    test("3+3j");
    test("3+3ij");
    test("3j");
    test("-3j");
    test("-3ij");
    test("");
    test("DETHTONGUE!");
}

输出:

3-3i is 3,-3 still in stream: 
3 is 3,0 still in stream: 
-3i is 0,-3 still in stream: 
 3-3i is 3,-3 still in stream: 
3-3i  is 3,-3 still in stream:  
3  is 3,0 still in stream:  
-3i  is 0,-3 still in stream:  
3-3i 3-3i is 3,-3 still in stream:  3-3i
3 -3i is 3,0 still in stream:  -3i
Invalid: j3+3i
3j3i is 3,0 still in stream: j3i
Invalid: 3+3j
3+3ij is 3,3 still in stream: j
3j is 3,0 still in stream: j
-3j is -3,0 still in stream: j
-3ij is 0,-3 still in stream: j
Invalid: 
Invalid: DETHTONGUE!

关于C++ 如何验证与重载 >> 运算符一起使用的输入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39732090/

相关文章:

c++ - std::map<struct,struct>::find 没有找到匹配项,但是如果我通过 begin() 循环到 end() 我会在那里看到匹配项

c# - 如何在所有应用程序中模拟键盘输入?

c++ - Qt 5.1 qHash 错误

c++ - 使用模板类 C++ 重新创建 vector

ruby-on-rails - rails 4 URI 域错误参数

c# - 对 UserControl 进行验证工作

javascript - 使用 jQuery 设置复选框

html - 为什么我的 HTML 数字输入会卡在步骤 0.010000000000000009 上?

c++ - 显式加载 DLL

android - 在 android 中验证 "from date"和 "to date"