how to read the 1st column value (name, name2 and name3) using substr function?
name;adress;item;others;
name2;adress;item;others;
name3;adress;item;others;
I've wrote
cout << "Read data.." << endl;
if (dataFile.is_open()) {
i=-1;
while (dataFile.good()) {
getline (dataFile, line);
if (i>=0) patient[i] = line;
i++;
}
dataFile.close();
}
#include <string>
#include <iostream>
#include <fstream>
#include <vector>
int main()
{
std::fstream f("file.txt");
if(f)
{
std::string line;
std::vector<std::string> names;
while(std::getline(f, line))
{
size_t pos = line.find(';');
if(pos != std::string::npos)
{
names.push_back(line.substr(0, pos));
}
}
for(size_t i = 0; i < names.size(); ++i)
{
std::cout << names[i] << "\n";
}
}
return 0;
}
Like this:
int pos = s.find(';');
if (pos == string::npos) ... // Do something here - ';' is not found
string res = s.substr(0, pos);
You need to find the position of the first ';', and then take substr from zero to that position. Here is a demo on ideone.
You can ignore the rest of the line after the content before the first semicolon is read:
std::vector<std::string> patient;
std::string line;
while (std::getline(file, line, ';'))
{
patient.push_back(line);
file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
Related
My project is supposed to basically sum up the value of all ints on a line and print the word in the next line that amount of times. However, something is causing it to skip over the string line where the word but I am getting the summed value right.
Input file:
1,2,3
word
2,3,4
word2
Here is my code:
int main() {
std::ifstream in;
std::ofstream out;
std::string line;
in.open("input.txt");
out.open("output.txt");
while(std::getline(in, line)){
std::stringstream ss(line);
while(ss){
std::string word;
std::string number;
int a = 0;
while(std::getline(ss, number, ',')){
a = a + atoi(number.c_str());}
std::getline(ss, word);
for (int z = 0; z < a; z++){
out << word << ",";}
out << "\n";
}
}
return(0);
}
Output I'm getting:
,,,,,,
,,,,,,,,,
What I should be getting:
word,word,word,word,word,word
word2,word2,word2,word2,word2,word2,word2,word2
Change:
std::getline(ss, word);
To this:
// Gets the next line in input.txt and stores it in the variable 'word'
std::getline(in, word);
This is because during the while loop, ss is emptied (exhausted) by the nested while loop (the 2nd while loop) and has no words when it's contents are inserted into the variable 'word'.
Final code:
#include <iostream>
#include <fstream>
#include <sstream>
int main() {
std::ifstream in;
std::ofstream out;
std::string line;
in.open("input.txt");
out.open("output.txt");
while (std::getline(in, line)) {
std::stringstream ss(line);
while (ss) {
std::string word;
std::string number;
int a = 0;
while (std::getline(ss, number, ',')) {
a = a + atoi(number.c_str());
}
std::getline(in, word); // Changed line
for (int z = 0; z < a; z++) {
out << word << ",";
}
out << "\n";
}
}
return(0);
}
Ok, so here is the text of the file I am trying to read:
KEYS
a set of keys
3
LAMP
a brightly shining brass lamp
8
ROD
a black rod with a rusty star
12
Ok, so pretend that each line is evenly spaced, but there are 2 blank lines, (or tabs) between 8 and ROD. How would I skip that and continue with the program? I am trying to put each line into 3 vectors (so keys, lamp, and rod into one vector etc). Here is my code (but it does not skip the blank line).:
#include <string>
#include <iostream>
#include <sstream>
#include <vector>
#include <fstream>
using namespace std;
int main() {
ifstream objFile;
string inputName;
string outputName;
string header;
cout << "Enter image file name: ";
cin >> inputName;
objFile.open(inputName);
string name;
vector<string> name2;
string description;
vector<string> description2;
string initialLocation;
vector<string> initialLocation2;
string line;
if(objFile) {
while(!objFile.eof()){
getline(objFile, line);
name = line;
name2.push_back(name);
getline(objFile, line);
description = line;
description2.push_back(description);
getline(objFile, line);
initialLocation = line;
initialLocation2.push_back(initialLocation);
} else {
cout << "not working" << endl;
}
for (std::vector<string>::const_iterator i = name2.begin(); i != name2.end(); ++i)
std::cout << *i << ' ';
for (std::vector<string>::const_iterator i = description2.begin(); i != description2.end(); ++i)
std::cout << *i << ' ';
for (std::vector<string>::const_iterator i = initialLocation2.begin(); i != initialLocation2.end(); ++i)
std::cout << *i << ' ';
I think you can check to see if the string is empty thru std::getline. If it is, then you can ignore it or something like.
getline(objFile, line);
name = line;
while(name.length() == 0)
{
getline(objFile, line);
name = line;
}
name = line;
name2.push_back(name);
getline(objFile, line);
description= line;
while(description.length() == 0)
{
getline(objFile, line);
description = line;
}
description= line;
description2.push_back(description);
getline(objFile, line);
initialLocation = line;
while(initialLocation.length() == 0)
{
getline(objFile, line);
initialLocation = line;
}
initialLocation = line;
initialLocation2.push_back(initialLocation );
If i am correct then a line will have no length if it is blank and if it is we check again therefore ignoring it.
You can use std::getline() (As pointed out by many people) instead... which will yield each line one-by-one:
inline std::string ReadFile(std::ifstream& stream)
{
std::string contents;
std::string temporary;
while (std::getline(stream, temporary))
if (!std::all_of(temporary.begin(), temporary.end(), isspace))
contents.append(temporary + "\n");
return contents.substr(0, contents.size() - 1);
}
And yes, an example:
int main()
{
std::ifstream is("file.txt");
if (is.fail())
return 1;
auto const contents = ReadFile(is);
is.close();
std::cout << contents << std::endl;
std::cin.get();
return 0;
}
I want to extract data from a csv file but I have to get the number of rows and columns of the table first.
What I have so far is the following:
std::ifstream myfile(filename); // filename is a string and passed in by the constructor
if (myfile.is_open())
{
// First step: Get number of rows and columns of the matrix to initialize it.
// We have to close and re-open the file each time we want to work with it.
int rows = getRows(myfile);
std::ifstream myfile1(filename);
int columns = getColumns(myfile1);
if (rows == columns) // Matrix has to be quadratic.
{
std::ifstream myfile2(filename);
abwicklungsdreieck.set_Matrix(QuantLib::Matrix(rows, columns, 0)); // abwicklungsdreieck is initialised before
//...
}
else
{
std::cout << "\nNumber of rows has to equal number of columns.";
}
}
// [...]
int getRows(std::ifstream &myfile)
{
std::string line;
int rows = 0;
while (std::getline(myfile, line)) // While-loop simply counts rows.
{
rows++;
}
myfile.close();
return rows - 1;
}
int getColumns(std::ifstream &myfile)
{
std::string line;
char delimiter = ';';
size_t pos = 0;
int columns = 0;
while (std::getline(myfile, line) && columns == 0) // Consider first line in the .csv file.
{
line = line + ";";
while ((pos = line.find(delimiter)) != std::string::npos) // Counts columns.
{
line.erase(0, pos + 1);
columns++;
}
}
myfile.close();
return columns - 1;
}
This code is working. However, I have to open the file for three times which I do not like. Is there a way to evade this?
I was thinking about working with tempfiles in getRows() and getColumns() but the copying streams isn't possible since it doesn't make sense as I learned recently.
So, is there another way do that? Or can I for example evade the getline() and the line.erase() methods?
You can read the file line by line, convert each line to a stream, then read the columns on the stream:
std::ifstream myfile(filename);
if(!myfile) return 0;
std::string line;
while(std::getline(myfile, line))
{
std::stringstream ss(line);
std::string column;
while(std::getline(ss, column, ';'))
{
cout << column;
}
cout << "\n";
}
getline(myfile, line) will copy each row in to line.
Convert line to ss stream.
getline(ss, column, ';') will break the line in to columns.
Use std::stoi to convert the string in to integer.
If your matrix is based on std::vector, you can grow the vector one row at a time, so you don't need to know the size in advance.
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
void readfile(const std::string &filename)
{
std::vector<std::vector<int>> matrix;
std::ifstream myfile(filename);
if(!myfile) return;
std::string buf;
while(std::getline(myfile, buf))
{
int maxrow = matrix.size();
std::stringstream ss(buf);
matrix.resize(maxrow + 1);
cout << "break in to columns:" << buf << "\n";
while(std::getline(ss, buf, ';'))
{
try {
int num = std::stoi(buf);
matrix[maxrow].push_back(num);
}
catch(...) { }
}
}
for(auto &row : matrix) {
for(auto col : row)
cout << col << "|";
cout << "\n";
}
}
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <sstream>
using namespace std;
int main()
{
string line;
ifstream infile ("Input.csv");
vector<string> table;
string word;
if(infile.is_open())
{
getline(infile,line);
istringstream iss(line);
while(!iss.eof())
{
getline(iss,word, ',');
table.push_back(word);
}
}
for(int index=0; index<11; ++index)
{
cout<< "Element" << index << ":" << table.at(index) << endl ;
}
infile.close();
}
In the above program I am reading values from input file and splitting based on comma and finally storing the values into a vector.
when I print vector I am able to view only the first line of input file.
Input file:
CountryCode,Country,ItemCode,Item,ElementGroup,ElementCode,Element,Year,Unit,Value,Flag
100,India,3010,Population - Est. & Proj.,511,511,Total Population - Both sexes,1961,1000,456950,
100,India,3010,Population - Est. & Proj.,511,511,Total Population - Both sexes,1962,1000,466337,
100,India,3010,Population - Est. & Proj.,511,511,Total Population - Both sexes,1963,1000,476025,
100,India,3010,Population - Est. & Proj.,511,511,Total Population - Both sexes,1964,1000,486039,
Output:
Element0:CountryCode
Element1:Country
Element2:ItemCode
Element3:Item
Element4:ElementGroup
Element5:ElementCode
Element6:Element
Element7:Year
Element8:Unit
Element9:Value
Element10:Flag
Problem: Only 1st line is being printed
I suggest rewriting it like this:
int main()
{
string line;
ifstream infile ("Input.csv");
vector<string> table;
string word;
while(getline(infile, line))
{
istringstream iss(line);
while(getline(iss,word, ','))
{
table.push_back(word);
}
}
for(int index=0; index<11; ++index)
{
cout<< "Element" << index << ":" << table.at(index) << endl ;
}
infile.close();
}
The stream will return false from getline and most other operations whenever it is invalid. So if it didn't open, the while loop won't run. And when it reaches EOF, the while loop will stop. Much simpler to read this way I think.
You have several issues, addressed below:
int main()
{
std::string line;
std::ifstream infile ("Input.csv");
std::vector<std::string> table;
while (std::getline(infile, line)) // this is the loop you want to read the file
{
std::istringstream iss(line);
std::string word;
while (std::getline(iss, word, ',')) // there are better ways to do this, but this will work
{
table.push_back(word);
}
}
for(int index=0; index<table.size(); ++index) // loop through the whole size
{
std::cout<< "Element" << index << ":" << table[index] << std::endl ;
}
infile.close();
return 0;
}
Alternatively, you can avoid the use of nested while loops altogether:
struct csv_reader : std::ctype<char>
{
csv_reader() : std::ctype<char>(get_table()) {}
static std::ctype_base::mask const* get_table()
{
static std::vector<std::ctype_base::mask> rc(table_size, std::ctype_base::mask());
rc['\n'] = std::ctype_base::space;
rc[','] = std::ctype_base::space;
return &rc[0];
}
};
int main()
{
std::string line;
std::ifstream infile ("Input.csv");
csv_reader reader;
infile.imbue(std::locale(std::locale(), &reader);
std::vector<std::string> table{std::istream_iterator<std::string>(infile), std::istream_iterator<std::string>()};
// or
//std::vector<std::string> table;
//std::copy(std::istream_iterator<std::string>(infile), std::istream_iterator<std::string>(), std::back_inserter(table));
for(int index=0; index<table.size(); ++index) // loop through the whole size
{
std::cout<< "Element" << index << ":" << table[index] << std::endl ;
}
infile.close();
return 0;
}
You read only one line of the file
if(infile.is_open())
{
getline(infile,line);
istringstream iss(line);
while(!iss.eof())
{
getline(iss,word, ',');
table.push_back(word);
}
}
If you need to read all lines of the file then you can write instead
while (getline(infile,line))
{
istringstream iss(line);
while(!iss.eof())
{
getline(iss,word, ',');
table.push_back(word);
}
}
You only read the first line.
Add a loop with a condition like
while (getline(infile, line)) {
...
}
Your for loop only print the first 11 posts from the array.
You should it to the lenght of the array.
Not sure what the syntax is for c++ for length of the table but that should be the issue.
for(int index=0; index<table.size(); ++index)
{
cout<< "Element" << index << ":" << table.at(index) << endl ;
}
Currently,
I have this string us,muscoy,Muscoy,CA,,34.1541667,-117.3433333.
I need to parse US and CA. I was able to parse US correctly by this:
std::string line;
std::ifstream myfile ("/Users/settingj/Documents/Country-State Parse/worldcitiespop.txt");
while( std::getline( myfile, line ) )
{
while ( myfile.good() )
{
getline (myfile,line);
//std::cout << line << std::endl;
std::cout << "Country:";
for (int i = 0; i < 2/*line.length()*/; i++)
{
std::cout << line[i];
}
}
}
But i'm having an issue parsing to CA.
Heres some code I dug up to find the amount of ',' occurrences in a string but I am having issues saying "parse this string between the 3rd and 4th ',' occurrence.
// Counts the number of ',' occurrences
size_t n = std::count(line.begin(), line.end(), ',');
std::cout << n << std::endl;
You can use boost::split function (or boost::tokenizer) for this purpose. It will split string into vector<string>.
std::string line;
std::vector<std::string> results;
boost::split(results, line, boost::is_any_of(","));
std::string state = results[3];
It's not for a class... Haha... it seems like a class question though...
I have the solution:
int count = 0;
for (int i = 0; i < line.length(); i++)
{
if (line[i] == ',')
count++;
if (count == 3){
std::cout << line[i+1];
if (line[i+1] == ',')
break;
}
}
Just had to think about it more :P
This is STL version, works pretty well for simple comma separated input files.
#include<fstream>
#include <string>
#include <iostream>
#include<vector>
#include<sstream>
std::vector<std::string> getValues(std::istream& str)
{
std::vector<std::string> result;
std::string line;
std::getline(str,line);
std::stringstream lineS(line);
std::string cell;
while(std::getline(lineS,cell,','))
result.push_back(cell);
return result;
}
int main()
{
std::ifstream f("input.txt");
std::string s;
//Create a vector or vector of strings for rows and columns
std::vector< std::vector<std::string> > v;
while(!f.eof())
v.push_back(getValues(f));
for (auto i:v)
{
for(auto j:i)
std::cout<<j<< " ";
std::cout<<std::endl;
}
}