简体   繁体   中英

C++ Specify input from istream and test it

I have a class basically representing a tuple (double x, doubly y) and I have overloaded the << operator so I can print the class. Now I want to do the same for >>, so that it only supports following formats: x, (x) and (x,y).

I jave following code:

std::ostream & operator<< (std::ostream &output, tuple &c){
    output << "(" << c.x << "," << c.y << ")" << endl;
    return output;
}

std::istream & operator>> (std::istream & input, tuple &c){
    // Check for following patterns: x, (x) or (x,y)
}

Can I loop through input and regex match? In that case how? Also how could I test that it's actually working, something like this std::cin >> "(10.2,5.5)"
or do I need to read from a file to test?

Edit: The answer given did solve this problem, but I wanted to add a way to test it as it might be to use of someone other than me:

tuple x(6,2);
stringstream ss;
ss << x;
ASSERT_EQUALS(ss.str(), "(6,2)\n");

Regex would just be unnecessary for a simple input task such as this. Here is how I would do it, without any checking for valid input or not, just parsing:

std::istream & operator>> (std::istream & input, tuple &c){
    // Check for following patterns: x, (x) or (x,y)
    char firstCharacter;
    input >> firstCharacter; // See what the first character is, since it varies

    if (firstCharacter == '(')
    {   // The simplest case, since the next few inputs are of the form n,n)
        char delimiters;
        input >> c.x >> delimiters >> c.y >> delimiters;
        //        N        ,           N        )
        // You also here have to check whether the above inputs are valid, 
        // such as if the user enters a string instead of a number
        // or if the delimeters are not commas or parentheses
    }
    else if (isdigit(firstCharacter) || firstCharacter == '-')
    {   //                               For negative numbers
        char delimiters;
        input.unget(); // Put the number back in the stream and read a number
        input >> c.x >> delimiters >> delimiters >> c.y >> delimiters;
        //        N           ,         (            N          )
        // You also here have to check whether the above inputs are valid, 
        // such as if the user enters a string instead of a number
        // or if the delimeters are not commas or parentheses
    }
    else
    { 
        // Handle some sort of a parsing error where the first character 
        // is neither a parenthesis or a number
    }

    return input;
}

A little late to the party, but here is regex solution. While it is not pretty, it allows for negative numbers input as well as scientific notation. It also will tolerate spaces between numbers:

#include <iostream>
#include <regex>
#include <tuple>

std::istream &operator>> (std::istream &input, std::tuple<double, double> &t)
{
    std::smatch m;
    std::string s;
    if (std::getline(input, s))
    {
        if (std::regex_match(s, m, std::regex(R"(\s*([-+]?\d*\.?\d+(?:[eE][-+]?\d+)?)\s*)"))) //x
            t = std::move(std::make_tuple(std::stod(m[1]), 0.0));
        else if (std::regex_match(s, m, std::regex(R"(\s*\(\s*([-+]?\d*\.?\d+(?:[eE][-+]?\d+)?)\s*\)\s*)"))) //(x)
            t = std::move(std::make_tuple(std::stod(m[1]), 0.0));
        else if (std::regex_match(s, m, std::regex(R"(\s*\(\s*([-+]?\d*\.?\d+(?:[eE][-+]?\d+)?)\s*,\s*([-+]?\d*\.?\d+(?:[eE][-+]?\d+)?)\s*\)\s*)"))) //(x,y)
            t = std::move(std::make_tuple(std::stod(m[1]), std::stod(m[2])));
    }
    return input;
}


int main() 
{
    std::tuple <double, double> t;
    std::cout << "Enter data in format num, (num) or (num1,num2): ";
    std::cin >> t;
    std::cout << "Tuple 0: " << std::get<0>(t) << std::endl;
    std::cout << "Tuple 1: " << std::get<1>(t) << std::endl;

    return 0;

} 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM