I have a file that contains a list of books. Each book has 4 variables delimitated by a Tab.
The variables are
- Title
- author
- isbn
- qty
and there are around 400 book entries.
I have managed to write a function that reads each input to an array and saves it to a Book object.
void loadFile() {
std::ifstream inputFile("books");
std::string bookArray[4];
std::string line;
Book book;
while (getline(inputFile, line)) {
size_t field2 = 0;
size_t field1 = line.find("\t");
for (int i = 0; i <= 3; i ) {
size_t field1 = line.find("\t" , field2);
if (field1 != std::string::npos) {
std::string str2 = line.substr(field2, field1 - field2);
bookArray[i] = str2;
}
field2 = field1 1;
}
book.setTitle(bookArray[0]);
book.setAuthor(bookArray[1]);
book.setIsbn(bookArray[2]);
book.setQty(stoi(bookArray[3]));
std::cout << "Book: " <<book.getTitle <<'\t'<< book.getQty<< " records.\n";
}
but the function seems to not pick up the qty numbers at the end of each line. Everything else seems to be fine except the qty numbers. I cant find what's wrong with the function.
I have tried implementing the same getline()
function with a '\t' delimitator argument like so:
while(getline(input, line, '\t')) {
The output just read the title of the first line and stopped there. I know the first function works.
Why is it not picking up the qty values?
The books file format is as follows:
A First Look at Graph Theory Clark John; Holton Derek Allan 9788170234630 5
A Practical Approach To Data Structures And Algorithms Sanjay Pahuja 9788122420678 7
A Practical Approach to High-Performance Computing Sergei Kurgalin; Sergei Borzunov 9783030275587 6
A Practical Guide to UNIX for Mac OS X Users Mark G. Sobell; Peter Seebach 9780321629982 5
A River Marc Martin 9781452162256 4
Total Noob here so I apologize if my code is awkward.
CodePudding user response:
The reason is that there's (likely) no tab character at the end of the line after the qty. So when you call line.find("\t", field2)
the 4th time, it returns string::npos
and you don't store anything in bookArray[3]
The best fix is probably to put an else
there with the if:
} else {
std::string str2 = line.substr(field2, std::string::npos);
bookArray[i] = str2;
break; // there can be no more fields on the line
be aware that if you have a line with fewer than 4 fields, the elements of bookArray
for the unfound fields will not be touched (so will continue to have values from the previous line)
CodePudding user response:
Chris Dodd's answer explains why your code is failing to parse the qty
values.
As an alternative solution, I would suggest using a std::istringstream
to parse each line
with std::getline()
, let it handle the searching and splitting for you 1, eg:
void loadFile() {
std::ifstream inputFile("books");
std::string bookArray[4];
std::string line;
Book book;
while (std::getline(inputFile, line)) {
std::istringstream iss(line);
for(int i = 0; i < 4; i) {
std::getline(iss, bookArray[i], '\t');
}
book.setTitle(bookArray[0]);
book.setAuthor(bookArray[1]);
book.setIsbn(bookArray[2]);
book.setQty(stoi(bookArray[3]));
std::cout << "Book: " << book.getTitle << '\t' << book.getQty << " records.\n";
}
}
1: there are, of course, many different ways to tokenize a string on a delimiter.
Alternatively, let the istringstream
handle the conversion of the qty
to an int
for you, no need to call std::stoi()
manually:
void loadFile() {
std::ifstream inputFile("books");
std::string bookArray[3];
int qty;
std::string line;
Book book;
while (std::getline(inputFile, line)) {
std::istringstream iss(line);
for(int i = 0; i < 3; i) {
std::getline(iss, bookArray[i], '\t');
}
iss >> qty;
book.setTitle(bookArray[0]);
book.setAuthor(bookArray[1]);
book.setIsbn(bookArray[2]);
book.setQty(qty);
std::cout << "Book: " << book.getTitle << '\t' << book.getQty << " records.\n";
}
}