istream& operator>>(istream& s, vector<Order>& ord) {
string c{};
bool got_customer = false;
Customer temp_customer{};
vector<Purchase>vec_purchase{};
while (s >> c) {
cout << "Erstes Wort der Zeile: "<<c << endl;
if (!got_customer) { //c[0] == '#'
c.erase(c.begin()); //löscht erstes Element vom string
int k_nummer{};
string k_vname{};
string k_nname{};
string k_plz{};
string k_stadt{};
k_nummer = stoi(c); //string to int
s >> k_vname >> k_nname >> k_plz>>k_stadt;
k_vname += " " + k_nname;
temp_customer = Customer(k_nummer, k_vname, k_plz, k_stadt);
got_customer = true;
} else {
string p_name{};
double p_preis{};
int p_menge{};
p_name = c;
s >> p_preis>>p_menge;
cout << p_name << " " << p_preis << " " << p_menge << endl;
vec_purchase.push_back(Purchase{p_name, p_preis, p_menge});
}
cout<<s.peek()<<endl;
if (s.peek() == '#') {
ord.push_back(Order{temp_customer, vec_purchase});
temp_customer = Customer{};
vec_purchase.clear();
got_customer = false;
}
}
}
Это текстовый файл:
#725454 Schenker Rudolf DE-30159 Hannover
Shirt 135.95 1
Tie 89.59 1
#987654 Orbison Roy US-TN37075 Hendersonville
Mug 1.49 3
T-Shirt 14.90 1
#123456 Petty Tom US-FL32641 Gainesville
Flashlight 12.95 2
#246802 Hite Bob US-CA90291 Venice
CannedBeans 0.89 10
CannedTomatoes 1.79 6
#246802 Hite Bob US-CA90291 Venice
CanOpener 0.48 1
Spoon 1.49 4
Needle 0.05 100
Строки, начинающиеся с ‘#’, являются объектами Customer.
Другие строки — объекты покупки.
Я пытаюсь заглянуть в предстоящий символ, но я получаю один и тот же символ снова и снова. В этом случае я всегда получаю «13» как результат s.peek ().
€ ДИТ:
Спасибо @ Марк Рэнсом.
Вот рабочий код, если у кого-то есть такая же проблема. 🙂
istream& operator>>(istream& s, vector<Order>& ord) {
string c{};
bool got_customer = false;
Customer temp_customer{};
vector<Purchase>vec_purchase{};
while (s >> c) {
if (!got_customer) {
c.erase(c.begin()); //deletes first char of string
int k_nummer{};
string k_vname{};
string k_nname{};
string k_plz{};
string k_stadt{};
k_nummer = stoi(c); //string to int
s >> k_vname >> k_nname >> k_plz>>k_stadt>>ws;
k_vname += " " + k_nname;
temp_customer = Customer(k_nummer, k_vname, k_plz, k_stadt);
got_customer = true;
} else {
string p_name{};
double p_preis{};
int p_menge{};
p_name = c;
s >> p_preis>>p_menge>>ws;
vec_purchase.push_back(Purchase{p_name, p_preis, p_menge});
}
if (s.peek() == 35||s.peek() == -1 ) { //35 (in ascii) -> # , -1 -> end of txt file
ord.push_back(Order{temp_customer, vec_purchase});
temp_customer = Customer{};
vec_purchase.clear();
got_customer = false;
}
}
}
Когда вы читаете из потока, ввод останавливается на первом символе пробела. Символ с десятичным кодом 13 является ASCII CR, которая находится в конце каждой строки в Windows; это считается пробелом. Вам нужно пропустить пробел, чтобы найти следующий значительное персонаж. Вы делаете это с std::ws
.
s >> k_vname >> k_nname >> k_plz >> k_stadt >> std::ws;
s >> p_preis >> p_menge >> std::ws;
s >> p_preis>>p_menge;
Это предназначено для чтения двух последних полей в строке с записью. Сразу после этого:
if (s.peek() == '#') {
Ваше очевидное намерение здесь состоит в том, чтобы заглянуть в первый символ на следующей строке, чтобы проверить, начинается ли следующая строка с #
, или нет.
Ну, этого не произойдет, вот так …
Проблема в том, что >>
оператор не потребляет символ конца строки после обработанного ввода. peek()
здесь вы получите символ новой строки. Сюрприз.
Учитывая пример строки ввода:
Tie 89.59 1
Часть «1» будет прочитана >>p_menge
и хранится в menge
, Следующий персонаж после 1
будет символом новой строки, и вот что peek()
с радостью дам тебе.
Это совершенно неправильный подход к этой задаче. Существует только один правильный подход для чтения файлов, содержащих строки текста:
std::getline()
Вот и все. std::getline()
, и ничего больше. Узнайте, как его использовать. Я сделаю вашу жизнь намного проще.
Вы, конечно, можете использовать >>
Оператор для чтения строк из вашего входного файла, по частям, по одному полю за раз, но, как вы обнаружили, это подверженный ошибкам и хрупкий процесс. Слишком много минных полей и подводных камней.
Ну, конечно, это можно сделать правильно, используя >>
оператор, но не всегда очевидно, как это сделать, и нужно полностью понимать все нюансы форматированных операций ввода.
К сожалению, слишком много вводных книг по C ++ начинаются сразу, представляя примеры, которые используют >>
оператор для чтения ввода, состоящего из строк текста. Это только сбивает с толку большинство начинающих, и приводит к проблемам и недоразумениям, как эти.
Вам нужно переписать вашу программу для использования std::getline()
читать по одной строке текста за раз. Конец истории.
Как только вы прочитаете всю строку текста в std::string
и проверил, начинается ли он с #
характер: если тебе так хочется затем Вы можете заполнить всю строку в std::istringstream
, а затем используйте >>
оператор, в контролируемой среде.