简体   繁体   中英

How to ensure user inputs a first and last name when only prompting for input once on one line?

C++ beginner here. I am storing structs of playerData in a vector (referred to as the player bank). One member of the struct is the player's name (stored in the struct as 1 string like "Julio Jones"). While using my application, if the user inputs a name that is not in my program's premade bank of players, the user is prompted to add the new name to the player bank for future use. The name input code is:

std::string input{};
std::cout << "Enter the player " << m_name << " traded: ";
std::getline(std::cin, input);

At the end of using the program, the user can save any changes they have made to the player bank for future use. I did so by writing the vector to a txt file

if (startAnswer == "exit")
{
    std::cout << "Exiting Trade Analzyer...\n";
    std::ofstream myfile;
    myfile.open("playerbank.txt");
    for (int k = 0; k < allPlayers.size(); ++k)
    {
        myfile << allPlayers[k].playerName << ' ' << allPlayers[k].playerPosition << ' ' << allPlayers[k].playersTeam << ' ' << allPlayers[k].playerValue << '\n';
    }
    myfile.close();
    return 0;
}

There are no issues at this point. However, the issue arises the next time the user tries to run the program and use their updated player bank: any new player they had previously entered into the bank that only had a first name will not be extracted from the txt file because I extract the values as follows:

std::istream& operator>> (std::istream& input, playerData& data)
{
    std::string first;
    std::string last;;
    input >> first >> last;
    input >> data.playerPosition;
    input >> data.playersTeam;
    input >> data.playerValue;
    data.playerName = first + ' ' + last;
    return input;
}

std::vector<playerData> createPlayerBankFromFile()
{
    std::vector<playerData> playerBank{};
    playerData playerStruct;
    std::ifstream inFile;
    inFile.open("playerbank.txt");
    while (inFile >> playerStruct)
    {
        playerBank.push_back(playerStruct);
    }
    inFile.close();
    return playerBank;
}

The issue is of course that I am trying to extract two strings, but there is only 1 when it encounters a new player struct that the user added to the player bank with only a first name. It seems to me that an easy solution to this would be to write a loop to ensure that the user inputs both a first and last name when creating new players, but how can I do so? I could do two extraction lines like:

std::string first;
std::string last;
std::cout << "Enter player's first name: ";
std::getline(std::cin, first);
std::cout << "Enter the player's last name: ";
std::getline(std::cin, last);

then concatenate the strings to make the full player name, but I'd like to prompt the user once and get the full player name in one line.

You are assuming that people have only 1 first name and 1 last name separated by 1 space. Names are not always that simple.

You should prompt the user for 1 string, save that to the playerName , and then store the entire playerName as-is to your file followed by a delimiter that is guaranteed to never appear in any name, whether that be a line break, or any other character you want (other than space), eg:

myfile.open("playerbank.txt");
for (int k = 0; k < allPlayers.size(); ++k)
{
    myfile << allPlayers[k].playerName << '|' << ... << '\n';
}
myfile.close();

Then, when reading back a name from the file, you can use std::getline() to read directly into playerName (get rid of first and last completely) until your chosen delimiter is reached, eg:

#include <limits>

std::istream& operator>> (std::istream& input, playerData& data)
{
    // read until the delimiter is reached...
    std::getline(input, data.playerName, '|');

    // read the other values from input as needed...

    // don't forget to read and discard the trailing line break at the end!
    input.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

    return input;
}

Alternatively:

#include <sstream>

std::istream& operator>> (std::istream& input, playerData& data)
{
    std::string line;
    if (!std::getline(input, line)) //<-- handles the trailing line break for you
        return input;

    std::istringstream iss(line);

    // read until the delimiter is reached...
    std::getline(iss, data.playerName, '|');

    // read the other values from iss as needed...

    return input;
}

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