C ++ Beginner - лучший способ прочитать 3 последовательных значения из командной строки? - PullRequest
0 голосов
/ 14 мая 2010

Я пишу текстовую реализацию 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 вызовет сбои, если пользователь испортит.

A getline и последующий синтаксический анализатор string являются допустимым решением, но представляют собой небольшую работу.

Есть ли другой, лучший способ сделать это, которого мне не хватает?

Спасибо за ваше время!

Ответы [ 4 ]

2 голосов
/ 14 мая 2010

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 голосов
/ 14 мая 2010

Извините, но getline и разбор строки - ваш лучший выбор.Однако вы можете сделать свою систему более удобной для повторного использования, создав класс для представления параметров ввода, а затем перегрузив оператор >>, чтобы он использовал getline и анализировал строку.Таким образом, вам не нужно повторять код разбора.

1 голос
/ 14 мая 2010

Я получил что-то вроде этого:

#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. Вы получаете сообщение об ошибке, что вы ввели неверный ввод для столбца, но как только вы успешно введете действительное число, вам все равно придется ввести ориентация снова. Таким образом, пользователь не имеет четкого представления об этом на основе этого приложения. Вы можете легко внести такие изменения, чтобы, если вы введете неверный ввод, вам будет предложено ввести все это.

0 голосов
/ 14 мая 2010

Еще одно предложение - вводить данные с консоли, используя по одному элементу за раз, и применять проверку ошибок:

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";
   }
}

Читая одну переменную за раз, а не все три одновременно, вы можете заранее предупредить пользователя об обнаружении ошибки.

...