3

I am trying to find out as to how I would print out the entire line from a CSV that contains a specific keyword. For example, I am attempting to only scrape the lines from the CSV file that contain "Back Bay". Here is the code

#include <iostream>
#include <fstream>
using namespace std;
int main()
{
    ifstream myfile("cabs.csv");

    while (myfile.good())
    {
        string line;
        string find = "Back Bay";
        getline(myfile, line, ',');
        if (strstr(line.c_str(),find.c_str()))
        {
            cout << line << endl;
        }
        
    }
}

Here is the snippet of the CSV file:

2.61,Lyft,1543428487883,South Station,Back Bay,27.5,1.0,2cccac4a-57dc-4dbe-b531-bb529335e898,lyft_lux,Lux Black
2.61,Lyft,1543428487883,South Station,Back Bay,7,1.0,38504f2f-300c-4e1b-bff4-4b44c3b4b842,lyft_line,Shared
2.61,Lyft,1543428487883,South Station,Back Bay,10.5,1.0,3ec303ac-a8b2-4fb8-add2-c83b61c627b5,lyft,Lyft
2.07,Lyft,1543428487883,North End,Beacon Hill,16.5,1.0,7b0c4e8d-21fc-4350-9972-f8dace1177ad,lyft_premier,Lux
2.07,Lyft,1543428487883,North End,Beacon Hill,10.5,1.0,9df49a6e-662d-4ac9-b003-34e3f146a209,lyft,Lyft
2.07,Lyft,1543428487883,North End,Beacon Hill,22.5,1.0,b7d55026-7809-4b7a-b275-27648f79cb8a,lyft_lux,Lux Black

So far my output only prints out the text "Back Bay"(however many times it occurs) but I would like it to also return the entire line of values. =>

from this:

Back Bay
Back Bay
Back Bay

to this:

2.61,Lyft,1543428487883,South Station,Back Bay,32.5,1.0,e1f1d1e3-f66a-4c12-94a6-62f59aff739b,lyft_luxsuv,Lux Black XL
2.61,Lyft,1543428487883,South Station,Back Bay,22.5,1.0,ed7e441e-8318-4c89-9499-8d4737bad7b5,lyft_premier,Lux
3.45,Uber,1543474677639,South Station,Back Bay,,1.0,09ede7b3-2e9b-43b4-8837-a58efb2e4d7a,8cf7e821-f0d3-49c6-8eba-e679c0ebcf6a,Taxi
user438383
  • 5,716
  • 8
  • 28
  • 43
Anon
  • 35
  • 6
  • 2
    Side note: `while (myfile.good())` tests that the stream is good and enters the loop. It cannot help you if the subsequent `getline(myfile, line, ',');` fails. When reading a stream, or pretty much anything, You need to read, test whether or not the read succeeded, use the data read if the read succeeded. Read, test, use. Any other ordering is a bug. – user4581301 Nov 08 '21 at 22:27
  • 1
    Side note: Consider replacing `strstr` with [`std::string::find`](https://en.cppreference.com/w/cpp/string/basic_string/find). I doubt you'll see any change in performance, but the code will be more idiomatic. In C++23 we'll likely have `std::string::contains`, and that'll be a no-brainer for anyone reading the code. – user4581301 Nov 08 '21 at 22:33
  • Consider modeling a `struct` to the record (text line). You could then build a database by reading in the records and storing into a `std::vector`. Next, search the database for your record(s) and print them. – Thomas Matthews Nov 08 '21 at 23:18
  • @Anon. Would you kindly communicate with us. Are the answers sufficient or do you need more help? – A M Nov 09 '21 at 16:53

2 Answers2

1

getline(myfile, line, ','); will not read the whole line but only the values between "," so that you print only "Back Bay". If the position of "Back Bay" does not matter, you can use:

std::ifstream input("cabs.csv" );

for( std::string line; getline( input, line ); )
{
   if (line.find("Back Bay") != std::string::npos) {
      std::cout << line << endl;
   }
}
jmj_
  • 11
  • 2
  • This same answer to the same question I gave already yesterday. Please see here. Obviously it was not sufficient. Therefore I addedd a more detailed answer today. – A M Nov 09 '21 at 16:43
1

I am always happy to help. Good, that I answered this question already yesterday here, because then it is easier for me.

I had already explained in detail and shown 4 examples, how to split a string into its parts.

You have chosen the std::getline approach. Very good and most often used.


I need to explain in more detail:

So, all we need to do to solve this task:

  1. Define the string that shall be found as a const std::string
  2. Open the source csv file, the check, if it could be opened
  3. After the file has been opened successfully, use a for loop, to read all lines in the source csv file
  4. Put the read line (a std::string) into a std::stringstream, so that we can extract parts out of it
  5. For the fun of it we define a rowCounter and a columnCounter, to keep track, where we are.
  6. In a simple for loop, extract all parts of the original string until the next ','
  7. In the for loop body, compare the single extracted part with the defined search string. Also check, if we are in column 4, or in part 4, where the text should be
  8. If we found the search string, then output the complete line

The above design can be implemented line by line.

The result could be:

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>

int main () {

    // The string to be searched
    const std::string find{"Back Bay"};
    
    // Open the source file and check, if it could be opened
    if (std::ifstream myfile{"cabs.csv"}; myfile) {
        
        // Ok, now the file is open. Next, read complete lines of the source
        // file until we hit EOF
        for (std::string line{}; std::getline(myfile, line); ) {
            
            // Put the line in a std::istringstream, so that we can extract the 
            // single parts of it that are separated by a ','
            std::istringstream iss{ line };
            
            // Now extract the single parts of the lines
            // Extract string parts in simple for loop.
            // We will also count in which row and column we are
            int rowCounter{}, columnCounter{};
            
            for (std::string part{}; std::getline(iss, part, ','); ++rowCounter,++columnCounter) {
                
                // If we find the search string in the correct column
                if ((part == find) and (columnCounter == 4))
                
                    // Search string found. Show complete line
                    std::cout << "Row: " << rowCounter << '\t' << line << '\n';
            }
        }
    }
    else std::cerr << "\n\n*** Error. Input file could not be opened\n\n";
    
    return 0;
}
A M
  • 14,694
  • 5
  • 19
  • 44