fstream — c ++ читает текстовый файл и копирует в два класса istream :: peek ()

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

0

Решение

Когда вы читаете из потока, ввод останавливается на первом символе пробела. Символ с десятичным кодом 13 является ASCII CR, которая находится в конце каждой строки в Windows; это считается пробелом. Вам нужно пропустить пробел, чтобы найти следующий значительное персонаж. Вы делаете это с std::ws.

s >> k_vname >> k_nname >> k_plz >> k_stadt >> std::ws;

s >> p_preis >> p_menge >> std::ws;
1

Другие решения

 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, а затем используйте >> оператор, в контролируемой среде.

0

По вопросам рекламы [email protected]