C ++ Beginner - 从命令行读取3个连续值的最佳方法?

时间:2010-05-14 14:55:14

标签: c++ parsing command-line input

我正在为大学项目编写一个基于文本的Scrabble实现。

规范规定必须从单行读取用户的位置输入,如下所示:

Coordinates of the word's first letter and orientation (<A – P> <1 – 15> <H ou V>): G 5 H 

G 5 H是该特定示例的用户输入。如图所示,订单必须为char int char

阅读用户输入的最佳方式是什么?

如果用户搞砸了,

cin >> row >> column >> orientation将导致崩溃。

getline和后续string解析器是有效的解决方案,但代表了一些工作。

还有另一种更好的方法吗?我错过了吗?

谢谢你的时间!

4 个答案:

答案 0 :(得分:2)

抱歉,getline和解析字符串是你最好的选择。但是,通过创建表示输入选项的类然后重载运算符&gt;&gt;,可以使系统更加可重用。所以它使用getline并解析字符串。这样,您就不必重复任何解析代码。

答案 1 :(得分:2)

getline并且解析不一定需要添加太多工作。由于您已经知道如何从流中读取(更正)数据,因此只需阅读getline行,然后从该行创建istringstream并从那里读取。

我要添加的一件事是,创建一个类来保存特定移动的数据,并且为该类重载operator>>以读取移动数据可能是有意义的。粗略的草图将是这样的:

class move { 
    char row;
    int column;
    char orientation;
public:
    friend std::istream &operator>>(std::istream &is, move &m);
};

std::istream &operator>>(std::istream &is, move &m) { 
    std::string temp;
    std::getline(is, temp);
    std::istringstream buffer(temp);

    // Now we can parse data from buffer just like we could from another stream.
    return is;
}

至少目前,我还没有包含任何错误处理代码。根据你想要的挑剔程度,这可能会有点棘手(例如,如果来自stringstream的输入失败,则在原始输入流中设置失败位。)

答案 2 :(得分:1)

我有这样的事情:

#include <iostream>
#include <limits>
#include <string>

using namespace std;

template<class T> T getValue(const string& name)
{
        T ret;
        while(!(cin >> ret))
        { 
                // normally here you'd go into an infinite loop, but since you're going to ignore the rest of the line, you can ensure that you won't go into an infinite loop and you can re-ask the user to input the correct data
                cout << "Invalid input for " << name << " please try again" << endl;
                cin.clear();
                cin.ignore(numeric_limits<streamsize>::max(), '\n');
        }
        return ret;
}

int main(void)
{
        bool valid = false;
        char row, orientation;
        int column;

        do {
                cout << "Enter row, column, and orientation (<A-P> <1-15> <H to V>): " << endl;
                row = getValue<char>("row");
                column = getValue<int>("column");
                orientation = getValue<char>("orientation");

                if(row<'A' || row>'P')
                        cout << "Invalid row please enter A-P" << endl;
                else if(column<1 || column>15)
                        cout << "Invalid column please enter 1-15" << endl;
                else if(orientation<'H' || orientation>'V')
                        cout << "Invalid orientation please enter H-V" << endl;
                else
                        valid = true;
        } while(!valid);

        cout << "Row: " << row << endl
             << "Column: " << column << endl
             << "Orientation: " << orientation << endl;

        return 0;
}

当然,如果你输入的内容如下:

A B C

这会产生一些可能令人困惑的问题。第一个A将成功复制到行char变量中。但是,由于B不是数字,它会忽略剩余的缓冲区,因此您会丢失B和C.您收到一条错误消息,表明您输入了无效的列输入,但是一旦成功输入有效数字,您仍然需要输入再次定位。因此,用户不清楚基于此应用程序的那一点。您可以轻松地进行此类修改,以便在输入无效输入时,它会重新输入您输入的内容。

答案 3 :(得分:0)

另一个建议是从控制台输入,一次使用一个项目并应用错误检查:

char row;
bool is_valid = false;
while (!is_valid)
{
   while (!(cin >> row))
   {
      cout << "Error reading row, please enter data again.\n";
   }

   row = toupper(row);
   static const std::string  valid_rows("ABCDEFGHIJKLMNO");
   is_valid = valid_rows.find(row) != std::string::npos;
   if (!is_valid)
   {
      cout << 'Row ' << row << ' is not a valid row letter, please re-enter.\n";
   }
}

通过一次读取一个变量而不是一次读取所有三个变量,您可以向用户提供有关错误检测的早期警告。