Reading .txt file and organizing into two-dimensional array - c++

I'm looking to take a somewhat lengthy text file 50 rows by 2 columns, have a user input the file name and read it into a two demensional array. The text file is a combination of organized names (including commas) and numbers.
I can get the console to display the text file itself, but I'm stuck when it comes to orgazing the data into the array. I'm trying to devise a loop code involving getline and find in order for program through sort through the .txt, stop at a comma and record every character before that comma into a location (i.e [0] [0]) of the array. I'm aware that using vectors would be easier, but I'd like to solve this with an array.
Also, there is the issue of reading names (strings) into the array (int).

Please test this code:
#include <vector>
#include <fstream>
#include <string>
#include <sstream>
#include <iterator>
template<typename Out>
void split(const std::string &s, char delim, Out result) {
std::stringstream ss;
ss.str(s);
std::string item;
while (std::getline(ss, item, delim)) {
*(result++) = item;
}
}
std::vector<std::string> split(const std::string &s, char delim) {
std::vector<std::string> elems;
split(s, delim, std::back_inserter(elems));
return elems;
}
int main()
{
std::ifstream file("test.txt", std::ios::binary);
std::string a, b;
int c;
std::vector<std::vector<std::string>> arr;
if (file)
{
while (file >> a )
{
std::vector<std::string> v = split(a, ',');
arr.push_back(v);
}
}
return 0;
}
my test.txt:
m,2
n,4
o,6
p,8
q,10

Related

string to numbers (vector array of int type)conversion

The function takes a string containing of comma(,) separated numbers as string and converts into numbers. Sometimes it produces a garbage value at the end.
vector<int> parseInts(string str)
{
int as[200]={0};
int i=0,j=0;
for(;str[i]!='\0';i++)
{
while(str[i]!=','&&str[i]!='\0')
{as[j]= as[j]*10 +str[i] -'0';
i++;}
j++;
}
vector<int>rr;
for(int i=0;i<j;i++)
rr.push_back(as[i]);
return rr;
}
If you're writing in C++, use C++ features instead of C-style string manipulation. You can combine std::istringstream, std::getline(), and std::stoi() into a very short solution. (Also note that you should take the argument by const reference since you do not modify it.)
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
std::vector<int> parseInts(std::string const & str) {
std::vector<int> values;
std::istringstream src{str};
std::string buf;
while (std::getline(src, buf, ',')) {
// Note no error checking on this conversion -- exercise for the reader.
values.push_back(std::stoi(buf));
}
return values;
}
(Demo)
The code doesn't handle whitespace and inputs with more than 200 numbers.
An alternative working solution:
#include <iostream>
#include <sstream>
#include <iterator>
#include <algorithm>
#include <vector>
std::vector<int> parseInts(std::string s) {
std::replace(s.begin(), s.end(), ',', ' ');
std::istringstream ss(std::move(s));
return std::vector<int>{
std::istream_iterator<int>{ss},
std::istream_iterator<int>{}
};
}
int main() {
auto v = parseInts("1,2 , 3 ,,, 4,5,,,");
for(auto i : v)
std::cout << i << '\n';
}
Output:
1
2
3
4
5
You never really asked a question. If you are looking for an elegant method, then I provide that below. If you are asking us to debug the code, then that is a different matter.
First here is a nice utility for splitting a string
std::vector<std::string> split(const std::string& str, char delim) {
std::vector<std::string> strings;
size_t start;
size_t end = 0;
while ((start = str.find_first_not_of(delim, end)) != std::string::npos) {
end = str.find(delim, start);
strings.push_back(str.substr(start, end - start));
}
return strings;
}
First split the string on commas:
std::vector<std::string> strings = split(str, ',');
Then covert each to an int
std::vector<int> ints;
for (auto s : strings)
ints.push_back(std::stoi(s))

C++ Writing a column of a CSV file into a vector

I have a CSV file with a bunch of columns, but I only need the information for the 11th column. How do I read through each line and skip to the 11th column in each line? I'm struggling to find clear information on how to read files in c++. This is what I have so far:
#include<iostream>
#include<fstream>
#include<vector>
#include <sstream>
#include <string>
std::string readStock(std::string fileName){
std::vector<std::string> ticker; //create vector
std::ifstream f(fileName, std::ios::in|std::ios:: binary|std::ios::ate);
std::string finalString = "";
if(f.is_open()){
std::string str;
std::getline(f,str); //skip the first row
while(std::getline(f,str)){ //read each line
std::istringstream s(str); //stringstream to parse csv
std::string val; //string to hold value
for(int i=1;i<=10;++i){ //skips everything until we get to the
column that we want
while(std::getline(s,val, ',')){
}
std::getline(s,val,',');
ticker.push_back(val);
}
f.close();
finalString = ticker.front();
}
}
else{
finalString="Could not open the file properly.";
}
return finalString;
}
int main(){
std::string st;
st=readStock("pr.csv");
std::cout<<st<<std::endl;
return 0;
}
There is a very simple solution for your problem.
You define a proxy class that reads one complete line, splits it into ALL tokens, using the dedicated functionality of the std::regex_token_iterator and then extracts the 11th element.
Using this proxy mechanism, you can use the std::istream_iterator to read the complete file, column 11, into a std::vector. For that we use the range constructor of the std::vector.
The result is a simple and short one-liner.
Please see:
#include <string>
#include <iostream>
#include <vector>
#include <fstream>
#include <regex>
#include <iterator>
#include <algorithm>
std::regex delimiter{ "," };
constexpr size_t targetColumn = 10U; // Target column is eleven
struct String11 { // Proxy for the input Iterator
// Overload extractor. Read a complete line
friend std::istream& operator>>(std::istream& is, String11& s11) {
// Read a complete line
if (std::string line{}; std::getline(is, line)) {
// Split it into tokens
std::vector token(std::sregex_token_iterator(line.begin(), line.end(), delimiter, -1), {});
// We only need one column
if (targetColumn < token.size()) {
// Get column 11
s11.result = token[targetColumn];
}
}
return is;
}
// Cast the type 'String11' to std::string
operator std::string() const { return result; }
// Temporary to hold the resulting string
std::string result{};
};
int main() {
// Open CSV fíle
if (std::ifstream csvFile{ "pr.csv" }; csvFile) {
// Read complete CSV file and get column 11 of each line
std::vector col11(std::istream_iterator<String11>(csvFile), {});
// Show output. Show all columns 11
std::copy(col11.begin(), col11.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
}
return 0;
}
EDIT:
For having output with doubles.
We just change one line in the cast operator in the proxy. That's all.
Even in main, there is no change in the read operatrion necessary. Through CTAD, the vector will be of type double.
Please see:
#include <string>
#include <iostream>
#include <vector>
#include <fstream>
#include <regex>
#include <iterator>
#include <algorithm>
std::regex delimiter{ "," };
constexpr size_t targetColumn = 10U; // Target column is eleven
struct String11 { // Proxy for the input Iterator
// Overload extractor. Read a complete line
friend std::istream& operator>>(std::istream& is, String11& s11) {
// Read a complete line
if (std::string line{}; std::getline(is, line)) {
// Split it into tokens
std::vector token(std::sregex_token_iterator(line.begin(), line.end(), delimiter, -1), {});
// We only need one column
if (targetColumn < token.size()) {
// Get column 11
s11.result = token[targetColumn];
}
}
return is;
}
// Cast the type 'String11' to double
operator double() const { return std::stod(result); }
// Temporary to hold the resulting string
std::string result{};
};
int main() {
// Open CSV fíle
if (std::ifstream csvFile{ "r:\\pr.csv" }; csvFile) {
// Read complete CSV file and get column 11 of each line
std::vector col11(std::istream_iterator<String11>(csvFile), {});
// Show output. Show all columns 11
std::copy(col11.begin(), col11.end(), std::ostream_iterator<double>(std::cout, "\n"));
}
return 0;
}
Output needs to adapted as well.

How to get array from txt in c++ [duplicate]

This question already has answers here:
How can I read and parse CSV files in C++?
(39 answers)
Closed 7 years ago.
Sorry if it's just pure stupidity but I'm stuck at a file reading problem via C++.
This is the CSV data that I'd like to read:
5;1;0;3;3;5;5;3;3;3;3;2;3;3;0
5;1;0;3;3;5;0;3;3;3;3;2;0;0;3
5;1;1;3;3;0;0;0;0;3;5;2;3;3;3
0;3;5;5;0;2;0;3;3;0;5;1;1;0;0
0;0;3;5;5;2;0;0;0;0;5;5;1;1;0
0;0;0;0;5;2;0;0;0;0;0;5;5;1;0
;;;;;;;;;;;;;;
Code;Bezeichnung;Kosten;;;;;;;;;;;;
0;Ebene;6;;;;;;;;;;;;
1;Fluss;10; (begrenzt nutzbar);;;;;;;;;;;
2;Weg;2;;;;;;;;;;;;
3;Wald;8;;;;;;;;;;;;
4;Brücke;5;;;;;;;;;;;;
5;Felswand;12;;;;;;;;;;;;
here, I'd like to read the first values (separated by ;;;;) and store it in a 2 dimensional array. Which would not be a problem if it was seperated completely by ';'. But if use
while (getline(csvread, s, ';'))
{
[...]
}
I get information like this: {5}{1}{0}{3}{3}{5}{5}{3}{3}{3}{3}{2}{3}{3}{0\n5}{1}
so it basically saves the newline and does not think of it as delimitator.
So is there an option to use getline even if you have two delimitators? Or am I completely off?
I also thought about reading it line by line to a string, adding a ; to the string and rewriting it in a file in order to reuse getline using ;. But this can't seriously be the best option, right?
You should do the '\n' and ';' splitting separately:
// here split into lines by '\n'
while (getline(csvread, line, '\n'))
{
// in here, split line by ;
std::vector<std::string> elems;
boost::split(elems, line, boost::is_any_of(";"));
// do something with elems
}
you can use a splitting function like :
std::vector<std::string> split(const std::string& source, const std::string& delimiter){
std::vector<std::string> result;
size_t last = 0;
size_t next = 0;
while ((next = source.find(delimiter, last)) != std::string::npos){
result.push_back(source.substr(last, next - last));
last = next + delimiter.length();
}
result.push_back(source.substr(last));
return result;
}
now simply:
std::vector<std::vector<std::string>> parsedCSV;
while (getline(csvread, s, '\n'))
{
parsedCSV.push_back(split(s,";"));
}
I recently had to read csv-data as well and stumbled upon the same 'problem'. Here's what I did:
Read in a full line with getline(csvread, s), this will read up to the first newline.
Split the string on every occurence of ;, I've used this StackOverflow answer as inspiration to split a string, the code is also listed below.
I didn't care much for performance as I only had to run this program once, I won't comment on the speed of this workaround.
Good luck!
Edit: apparently Boost offers code to split a string, that might be cleaner, consider the code below if you want to avoid Boost.
#include <string>
#include <sstream>
#include <vector>
// source: https://stackoverflow.com/a/236803/4841248
std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems) {
std::stringstream ss(s);
std::string item;
while (std::getline(ss, item, delim)) {
elems.push_back(item);
}
return elems;
}
std::vector<std::string> split(const std::string &s, char delim) {
std::vector<std::string> elems;
split(s, delim, elems);
return elems;
}
try something like this:
std::vector<std::string> cells;
while (getline(csvread, s) ){
boost::split(cells, s, boost::is_any_of(";"));
....
}

C++: Read CSV-file separated by ; AND \n [duplicate]

This question already has answers here:
How can I read and parse CSV files in C++?
(39 answers)
Closed 7 years ago.
Sorry if it's just pure stupidity but I'm stuck at a file reading problem via C++.
This is the CSV data that I'd like to read:
5;1;0;3;3;5;5;3;3;3;3;2;3;3;0
5;1;0;3;3;5;0;3;3;3;3;2;0;0;3
5;1;1;3;3;0;0;0;0;3;5;2;3;3;3
0;3;5;5;0;2;0;3;3;0;5;1;1;0;0
0;0;3;5;5;2;0;0;0;0;5;5;1;1;0
0;0;0;0;5;2;0;0;0;0;0;5;5;1;0
;;;;;;;;;;;;;;
Code;Bezeichnung;Kosten;;;;;;;;;;;;
0;Ebene;6;;;;;;;;;;;;
1;Fluss;10; (begrenzt nutzbar);;;;;;;;;;;
2;Weg;2;;;;;;;;;;;;
3;Wald;8;;;;;;;;;;;;
4;Brücke;5;;;;;;;;;;;;
5;Felswand;12;;;;;;;;;;;;
here, I'd like to read the first values (separated by ;;;;) and store it in a 2 dimensional array. Which would not be a problem if it was seperated completely by ';'. But if use
while (getline(csvread, s, ';'))
{
[...]
}
I get information like this: {5}{1}{0}{3}{3}{5}{5}{3}{3}{3}{3}{2}{3}{3}{0\n5}{1}
so it basically saves the newline and does not think of it as delimitator.
So is there an option to use getline even if you have two delimitators? Or am I completely off?
I also thought about reading it line by line to a string, adding a ; to the string and rewriting it in a file in order to reuse getline using ;. But this can't seriously be the best option, right?
You should do the '\n' and ';' splitting separately:
// here split into lines by '\n'
while (getline(csvread, line, '\n'))
{
// in here, split line by ;
std::vector<std::string> elems;
boost::split(elems, line, boost::is_any_of(";"));
// do something with elems
}
you can use a splitting function like :
std::vector<std::string> split(const std::string& source, const std::string& delimiter){
std::vector<std::string> result;
size_t last = 0;
size_t next = 0;
while ((next = source.find(delimiter, last)) != std::string::npos){
result.push_back(source.substr(last, next - last));
last = next + delimiter.length();
}
result.push_back(source.substr(last));
return result;
}
now simply:
std::vector<std::vector<std::string>> parsedCSV;
while (getline(csvread, s, '\n'))
{
parsedCSV.push_back(split(s,";"));
}
I recently had to read csv-data as well and stumbled upon the same 'problem'. Here's what I did:
Read in a full line with getline(csvread, s), this will read up to the first newline.
Split the string on every occurence of ;, I've used this StackOverflow answer as inspiration to split a string, the code is also listed below.
I didn't care much for performance as I only had to run this program once, I won't comment on the speed of this workaround.
Good luck!
Edit: apparently Boost offers code to split a string, that might be cleaner, consider the code below if you want to avoid Boost.
#include <string>
#include <sstream>
#include <vector>
// source: https://stackoverflow.com/a/236803/4841248
std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems) {
std::stringstream ss(s);
std::string item;
while (std::getline(ss, item, delim)) {
elems.push_back(item);
}
return elems;
}
std::vector<std::string> split(const std::string &s, char delim) {
std::vector<std::string> elems;
split(s, delim, elems);
return elems;
}
try something like this:
std::vector<std::string> cells;
while (getline(csvread, s) ){
boost::split(cells, s, boost::is_any_of(";"));
....
}

Attempting to get data from lines in a file

I'm quite new to C++, so sorry if this is a dumb question!
For a project we are given a file with a couple of thousand lines of values, each line having 9 different numbers.
I want to create a for/while loop that, for each loop, stores the 8th and 9th integer of a line as a variable so that I can do some calculations with them. The loop would then move onto the next line, store the 8th and 9th numbers of that line as the same variable, so that I can do the same calculation to it, ending when I've run out of lines.
My problem is less to do with reading the file, I'm just confused how I'd tell it to take only the 8th and 9th value from each line.
Thanks for any help, it is greatly appreciated!
Designed for readability rather than speed. It also performs no checking that the input file is the correct format.
template<class T> ConvertFromString(const std::string& s)
{
std::istringstream ss(s);
T x;
ss >> x;
return x;
}
std::vector<int> values8;
std::vector<int> values9;
std::ifstream file("myfile.txt");
std::string line;
while (std::getline(file, line))
{
std::istringstream ss(line);
for (int i = 0; i < 9; i++)
{
std::string token;
ss >> token;
switch (i)
{
case 8:
{
values8.push_back(ConvertFromString<int>(token));
}
break;
case 9:
{
values9.push_back(ConvertFromString<int>(token));
}
break;
}
}
}
First, split the string, then convert those to numbers using atoi. You then will take the 8th and 9th values from the array or vector with the numbers.
//Split string
std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems) {
std::stringstream ss(s);
std::string item;
while (std::getline(ss, item, delim)) {
elems.push_back(item);
}
return elems;
}
std::vector<std::string> split(const std::string &s, char delim) {
std::vector<std::string> elems;
split(s, delim, elems);
return elems;
}
//new code goes here
std::string line;
std::vector<std::string> lineSplit = split(line, ' ');
std::vector<int> numbers;
for (int i = 0; i < lineSplit.size(); i++)
numbers.push_back(atoi(lineSplit[i]);//or stoi
int numb1 = numbers[7];//8th
int numb2 = numbers[8];//9th