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

C++ how to validate input for use with overloaded >> operator

本文关键字:gt 重载 运算符 一起 何验证 验证 输入 C++      更新时间:2023-10-16

我正在编写一个可以对复数进行运算的程序。我有一个名为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 !,但我觉得如果我在第一个问题上得到帮助,我可以使用提供的信息来解决第二个问题。

我意识到这可能不是最好的措辞,我只是希望你理解我试图实现的目标。我真的很感谢你的帮助。谢谢

通常我会用状态机来完成这项工作。以前从未使用过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!