1

I'm trying to create a code that will parse through a csv database with stock information. Currently, I have the code generated so that it will search with a keyword and print the whole row, but I'm trying to get it so that it will print the whole row with the header row in a neatly formatted way.

I'm trying to get it so that if I searched Google, it'd return

Symbol GOOG
NAME Google Inc
High Today $568.77

How the csv looks like:

Symbol,Name,Price,High Today,Low Today,52 Week Low
GOOG,Google Inc.,$568.77 ,$570.25 ,$560.35
AAPL,Apple Inc.,$93.28 ,$63.89 ,$99.44.

Code:

string NameSearch::getInput()
{
    cout << "Enter the name of the company you would like to search for: ";
    getline(cin, input);
    return input;

}
void NameSearch::NameAlgorithm()
{
    string line;
    ifstream fs("Stock Database.csv");

    while (!fs.eof())
    {
        getline(fs, line);
        string companyname = "";    
        string a;
        int column = 1;             
        int commacount = 0;         
        int ChrCount = 0;               

        while (line != "\0")        
        {
            a = line[ChrCount];       
            ChrCount++;

            if (a == ",")
            {
                commacount++; 
            }

            else if (commacount == column) 
            {
                companyname.append(a);
            }

            else if (commacount > column) 
            {
                break;
            }

            if (companyname == input)
            {
                cout << endl << line;
            }
        }
    }
}
1
  • What is the last row for and how does it relate to your formatting requirements? Commented Aug 10, 2014 at 1:59

2 Answers 2

7

First a comma should be parsed as whitespace. You can do this by changing the internal std::ctype<charT> facet in the stream's locale:

struct csv_classification : std::ctype<char> {
    csv_classification() : ctype(make_table()) { }
private:
    static mask* make_table() {
        const mask* classic = classic_table();
        static std::vector<mask> v(classic, classic + table_size);
        v[','] |= space;
        v[' '] &= ~space;
        return &v[0];
    }
};

Then set the locale using:

ifs.imbue(std::locale(ifs.getloc(), new csv_classification));

Next make a manipulator that checks to see if you're at the end of the line. If you are it sets the std::ios_base::failbit flag in the stream state. Also use internal storage to tell if the record belongs as a key or value in the map. Borrowing a bit from Dietmar...

static int row_end = std::ios_base::xalloc();

std::istream& record(std::istream& is) {
    while (std::isspace(is.peek())) {
        int c(is.peek());
        is.ignore();

        if (c == '\n') {
            is.iword(row_end) = !is.iword(row_end);
            is.setstate(std::ios_base::failbit);
        }
    }
    return is;
}

Then you can do:

std::vector<std::string> keys, values;

for (std::string item;;) {
    if (ifs >> record >> item)
        keys.push_back(item);
    else if (ifs.eof())
        break;
    else if (ifs.iword(row_end)) {
        ifs.clear();
        while (ifs >> record >> item)
            values.push_back(item);
    }
    else
        break;
}

Now we need to apply both the keys and values and print them out. We can create a new algorithm for that:

template<class Iter1, class Iter2, class Function>
void for_each_binary_range(Iter1 first1, Iter1 last1,
                           Iter2 first2, Iter2 last2, Function f)
{
    assert(std::distance(first1, last1) <= std::distance(first2, last2));

    while (first1 != last1) {
        f(*first1++, *first2++);
    }
}

Finally we do:

for_each_binary_range(std::begin(keys),   std::end(keys),
                      std::begin(values), std::end(values),
[&] (std::string const& key, std::string const& value)
{
    std::cout << key << ": " << value << std::endl;
}

Live Demo

Sign up to request clarification or add additional context in comments.

12 Comments

This is an interesting answer but I don't get it why U return address of an scope variable from the function, U are returning address of internal buffer of the local vector variable(v) from function make_table
@BigBoss The vector and its contents have static storage duration so they exist for the duration of the program.
Sorry what I see is your function is static and your vector is local, what make your vector static?
Maybe you want: static std::vector<mask> v(classic, classic + table_size)
Sorry but this edit also have one problem, how you initialize an static vector from an scoped variable and why rest of initialization will be called multiple times for this. I think we should have something like this: static std::vector<mask> v(create_my_table()); return &v[0]; and create_my_table return a vector not a pointer or like of that.
|
0

Here it is your solution (the most close to what you requested):

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

using namespace std;

typedef std::vector<std::string> record;

std::istream&
operator>>(
  std::istream& is,
  record&       r)
{
  r.clear();

  string line;
  getline(is, line);

  istringstream iss(line);
  string field;

  while (getline(iss, field, ',' ))
    r.push_back(field);

  return is;
}

int
main()
{

  ifstream file("Stock Database.csv");
  record headers, r;

  if (file.good())
    file >> headers;

  while (file >> r)
  {
    for (int i = 0; i < r.size(); i++)
      cout << headers[i] <<  ":\t" << r[i] << endl;

    cout << "------------------------------" << endl;
  }

  return 0;
}

// EOF

The content of the "Stock Database.csv" file is:

Symbol,Name,Price,High Today,Low Today,52 Week Low
GOOG,Google Inc.,$568.77 ,$570.25 ,$560.35
AAPL,Apple Inc.,$93.28 ,$63.89 ,$99.44

Just do with the record whatever you want. The first read from the file suppose to bring you headers. Every next read fill each record with csv values.

9 Comments

All this does is print the stream. He wants it to be formatted like he showed in his question.
1 sec. I'll change the sample.
@Tanuki Sorry if this is obvious, I'm a beginner in c++, but does the above code take as input what's is searched or is in manually inputting the whole line? Because the csv above is just a small snippet of a larger database with more columns and rows.
@Tanuki Would I just replace this line here istringstream input("GOOG,Google Inc.,$568.77 ,$570.25 ,$560.35"); to input(line)
@Tanuki Thank you - I'll take a deeper look.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.