Home > OS >  Why does getline() not read the last int value in the line?
Why does getline() not read the last int value in the line?

Time:04-28

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