C ++如何验证输入以用于重载>>操作者

时间:2016-09-27 18:41:18

标签: 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 or !但我觉得如果我得到第一个问题的帮助,我可以使用给出的信息来解决第二个问题。

我意识到这可能不会以最好的方式措辞,我希望你能理解我想要实现的目标。我真的很感激任何帮助。感谢。

1 个答案:

答案 0 :(得分:1)

通常情况下,我会使用状态机来执行此操作。以前从未使用过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!