Is there a way to "dump" a value read using a stream without reading it into a dummy variable?
For example, if I have a file which contains two strings and an integer, e.g., "foo.txt" looks like this:
foo bar 6
foofoo barbar 8
Is it possible to do something like this:
std::string str;
int i;
std::ifstream file("foo.txt");
file >> str >> nullptr >> i;
and have str = "foo" and i = 6 afterwards?
There is std::basic_istream::ignore but it is pretty much useless because:
It can only skip one particular delimiter character, not a character class (e.g. any whitespace).
It needs to be invoked multiple times to skip a word.
You can write a function ignore_word(std::istream& s):
std::istream& ignore_word(std::istream& s) {
while(s && std::isspace(s.peek()))
s.get();
while(s && !std::isspace(s.peek()))
s.get();
return s;
}
int main() {
std::istringstream s("foo bar 6");
std::string foo;
int i;
s >> foo;
ignore_word(s);
s >> i;
std::cout << foo << ' ' << i << '\n';
}
Related
Okay I read that if we have a string s =" 1 2 3"
we can do :
istringstream iss(s);
int a;
int b;
int c;
iss >> a >> b >> c;
Lets say we have a text file with the following :
test1
100 ms
test2
200 ms
test3
300 ms
ifstream in ("test.txt")
string s;
while (getline(in, s))
{
// I want to store the integers only to a b and c, How ?
}
1) You can rely on succesful convertions to int:
int value;
std::string buffer;
while(std::getline(iss, buffer,' '))
{
if(std::istringstream(buffer) >> value)
{
std::cout << value << std::endl;
}
}
2) or just skip over unnecessary data:
int value;
std::string buffer;
while(iss >> buffer)
{
iss >> value >> buffer;
std::cout << value << std::endl;
}
If you know the pattern of the details in the text file, you could parse through all the details, but only store the int values. For example:
ifstream in ("test.txt")
string s;
while (getline(in, s))
{
getline(in,s); //read the line after 'test'.
string temp;
istringstream strm(s);
s >> temp;
int a = stoi(temp) // assuming you are using C++11. Else, atoi(temp.c_str())
s >> temp;
getline(in,s); // for the line with blank space
}
This above code is still somewhat of a inelegant hack. What you could do besides this is use random file operations in C++. They allow you to move your pointer for reading data from a file. Refer to this link for more information: http://www.learncpp.com/cpp-tutorial/137-random-file-io/
PS: I haven't run this code on my system, but I guess it should work. The second method works for sure as I have used it before.
I have a file filled with ints (variable amount on a line), delimited by a space. I would like to parse out the int, then space, then int, then space ... until the newline char then start at a new line until the eof. An example file would look something like this:
1 1 324 234 12 123
2 2 312 403 234 234 123 125 23 34
...
To grab the ints I can do something like this:
std::ifstream inStream(file.txt);
std::string line;
int myInt = 0;
while(getline(inStream, line)) {
std::stringstream ss(line);
while(ss) {
ss >> myInt;
//process...
}
}
My question is that is there an easy way to also get the whitespace and endline char from the ss? Or is my best bet to write my program assuming a space after each index and a newline at the end of the ss? something like this:
std::ifstream inStream(file.txt);
std::string line;
int myInt = 0;
while(getline(inStream, line)) {
std::stringstream ss(line);
while(ss) {
ss >> myInt;
// process...
// done with myInt
char mySpace = ' ';
// now process mySpace
}
char myNewLine = '\n';
// now process myNewLine
}
If performance is not the most important issue, the following would be a general-purpose tokenizer for your input format. Whether this is a feasible solution depends of course on what you actually want to do with the input.
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
static void handle_number_string(std::string& literal) {
if (!literal.empty()) {
std::istringstream iss {literal};
int value;
if (iss >> value) {
std::clog << "<" << value << ">";
} else {
// TODO: Handle malformed integer literal
}
literal.clear();
}
}
int main(int argc, char** argv) {
for (int i = 1; i < argc; i++) {
std::string aux;
std::ifstream istr {argv[i]};
std::clog << argv[i] << ": ";
while (istr.good()) {
const int next = istr.get();
switch (next) {
case ' ':
handle_number_string(aux);
std::clog << "<SPC>";
break;
case '\n':
handle_number_string(aux);
std::clog << "<EOL>";
break;
default:
aux.push_back(next);
}
}
// Handle case that the last line was not terminated with '\n'.
handle_number_string(aux);
std::clog << std::endl;
}
return 0;
}
Addendum: I'd only do this if I absolutely had to. Handling all possibilities (multiple spaces, non-breaking spaces, tabs, \r\n,…) correctly will be a lot of work. If what you actually want to handle are the logical tokens field separator and end of line, manually parsing whitespace seems to be the wrong way to go. It would be sad if your program crashes just because a user has justified the columns in the input file (thus using a variable number of spaces).
Try something like this:
std::ifstream inStream(file.txt);
std::string line;
int myInt;
while (std::getline(inStream, line))
{
std::stringstream ss(line);
ss >> myInt;
if (ss)
{
do
{
// process...
// done with myInt
ss >> myInt;
if (!ss) break;
char mySpace = ' ';
// now process mySpace
}
while (true);
}
char myNewLine = '\n';
// now process myNewLine
}
I have a .csv file that has 3 rows and 5 columns with values of 0,1,2,3,50, or 100. I saved it from an excel sheet to a .csv file. I am trying to use C++ to read in a .csv file and output the first two column values in the .csv file into a text file based on the last three column values. I am assuming the .csv file looks like
1,1,value,value,value
1,2,value,value,value
1,3,value,value,value
But I couldn't find a whole lot of documentation on the format of .csv files.
I looked at Reading Values from fields in a .csv file? and used some of the code from there.
Here is my code:
#include <iostream>
#include <fstream>
using namespace std;
char separator;
int test_var;
struct Spaxel {
int array1;
int array2;
int red;
int blue_o2;
int blue_o3;
};
Spaxel whole_list [3];
int main()
{
// Reading in the file
ifstream myfile("sample.csv");
Spaxel data;
int n = 0;
cout << data.array1<< endl;
myfile >> data.array1; // using as a test to see if it is working
cout << data.array1<< endl;
while (myfile >> data.array1)
{
// Storing the 5 variable and getting rid of commas
cout<<"here?"<< endl;
// Skip the separator, e.g. comma (',')
myfile >> separator;
// Read in next value.
myfile >> data.array2;
// Skip the separator
myfile >> separator;
// Read in next value.
myfile >> data.red;
// Skip the separator, e.g. comma (',')
myfile >> separator;
// Read in next value.
myfile >> data.blue_o2;
// Skip the separator
myfile >> separator;
// Read in next value.
myfile >> data.blue_o3;
// Ignore the newline, as it is still in the buffer.
myfile.ignore(10000, '\n');
// Storing values in an array to be printed out later into another file
whole_list[n] = data;
cout << whole_list[n].red << endl;
n++;
}
myfile.close();
// Putting contents of whole_list in an output file
//whole_list[0].red = whole_list[0].array1 = whole_list[0].array2 = 1; this was a test and it didn't work
ofstream output("sample_out.txt");
for (int n=0; n<3; n++) {
if (whole_list[n].red == 1)
output << whole_list[n].array1 <<","<< whole_list[n].array2<< endl;
}
return 0;
}
When I run it in Xcode it prints three 0's (from the cout << data.array1<< endl; and cout << data.array1<< endl; in the beginning of the main() and from the return 0) but does not output any file. Apparently the .csv file isn't getting read in correctly and the output file is not getting written correctly. Any suggestions?
Thanks for your time!
There are a couple of problem areas in the code you presented:
Hard coded filename. Running your program in a directory that doesn't have "sample.csv" could cause the ifstream failure you're seeing.
No checking whether myfile opened successfully or not.
Loop can access an out-of-bound index in whole_list if "sample.csv" has more lines.
The refactored code below, while not completely foolproof, corrects many of the issues mentioned. It should get you most of the way there.
#include <iostream>
#include <vector>
#include <fstream>
#include <sstream>
using namespace std;
struct Spaxel
{
int array1;
int array2;
int red;
int blue_o2;
int blue_o3;
};
ostream& operator << (ostream &os, const Spaxel &rhs)
{
os << rhs.array1
<< ','
<< rhs.array2
<< ','
<< rhs.red
<< ','
<< rhs.blue_o2
<< ','
<< rhs.blue_o3;
return os;
}
istream& operator >> (istream &is, Spaxel &rhs)
{
char delim;
is >> rhs.array1
>> delim
>> rhs.array2
>> delim
>> rhs.red
>> delim
>> rhs.blue_o2
>> delim
>> rhs.blue_o3;
return is;
}
int main(int argc, const char *argv[])
{
if(argc < 2)
{
cout << "Usage: " << argv[0] << " filename\n";
return 1;
}
const char *infilename = argv[argc - 1];
// Reading in the file
ifstream myfile(infilename);
if(!myfile)
{
cerr << "Couldn't open file " << infilename;
return 1;
}
vector<Spaxel> whole_list;
string line;
while( getline(myfile, line) )
{
Spaxel data;
stringstream linestr (line);
linestr >> data;
whole_list.push_back(data);
cout << data << '\n';
}
}
Edit: Just to help clarify some things from the comment.
As you know main is the entry point of your program so it isn't something called by your own code. The extra optional parameters int argc, const char *argv[], is how options and parameters get passed in when you run your program with arguments. First parameter argc indicates how many arguments were passed in. The second argv is an array of char * with each element being the argument passed. The first argument argv[0] is your program name and so argc is always >= 1.
Say you execute your sample program from the shell:
./sample sample.csv
then argc and argv will have the following:
argc = 2;
argv[0] = "sample"
argv[1] = "sample.csv"
So const char *infilename = argv[argc - 1]; gets the last argument passed in which should be the filename to read in.
Sorry i am not doing it within struct but i hope you will got it and resolve your problem.
char separator;
int value1;
int value2;
int value3;
while (myfile >> value1)
{
// Skip the separator, e.g. comma (',')
myfile >> separator;
// Read in next value.
myfile >> value2;
// Skip the separator, e.g. comma (',')
myfile >> separator;
// Read in next value.
myfile >> value3;
// Ignore the newline, as it is still in the buffer.
myfile.ignore(10000, '\n');
}
The above code fragment is not robust but demonstrates the concept of reading from a file, skipping non-numeric separators and processing the end of the line. The code is optimized either.
I have some trouble with reading of a file in C++. I am able to read only integers or only alphabets. But I am not able to read both for example, 10af, ff5a. My procedure is as follows:
int main(int argc, char *argv[]) {
if (argc < 2) {
std::cerr << "You should provide a file name." << std::endl;
return -1;
}
std::ifstream input_file(argv[1]);
if (!input_file) {
std::cerr << "I can't read " << argv[1] << "." << std::endl;
return -1;
}
std::string line;
for (int line_no = 1; std::getline(input_file, line); ++line_no) {
//std::cout << line << std::endl;
-----------
}
return 0;
}
So what I am trying to do is, I am allowing the user to specify the input file he wants to read, and I am using getline to obtain each line. I can use the method of tokens to read only integers or only alphabets. But I am not able to read a mix of both. If my input file is
2 1 89ab
8 2 16ff
What is the best way to read this file?
Thanks a lot in advance for your help!
I'd use a std::stringstream, and use std::hex since 89ab and 16ff look like hex numbers.
Should look like this:
std::string line;
for (int line_no = 1; std::getline(input_file, line); ++line_no)
{
std::stringstream ss(line);
int a, b, c;
ss >> a;
ss >> b;
ss >> std::hex >> c;
}
You will need to #include <sstream>
Using
std::string s;
while (input_file >> s) {
//add s to an array or process s
...
}
you can read inputs of type std::string which could be any combination of digits and alphabets. You don't necessarily need to read input line by line and then try to parse it. >> operator considers both space and newline as delimiters.
I want to read a txt file line by line and after reading each line, I want to split the line according to the tab "\t" and add each part to an element in a struct.
my struct is 1*char and 2*int
struct myStruct
{
char chr;
int v1;
int v2;
}
where chr can contain more than one character.
A line should be something like:
randomstring TAB number TAB number NL
Try:
Note: if chr can contain more than 1 character then use a string to represent it.
std::ifstream file("plop");
std::string line;
while(std::getline(file, line))
{
std::stringstream linestream(line);
std::string data;
int val1;
int val2;
// If you have truly tab delimited data use getline() with third parameter.
// If your data is just white space separated data
// then the operator >> will do (it reads a space separated word into a string).
std::getline(linestream, data, '\t'); // read up-to the first tab (discard tab).
// Read the integers using the operator >>
linestream >> val1 >> val2;
}
Unless you intend to use this struct for C as well, I would replace the intended char* with std::string.
Next, as I intend to be able to read it from a stream I would write the following function:
std::istream & operator>>( std::istream & is, myStruct & my )
{
if( std::getline(is, my.str, '\t') )
return is >> my.v1 >> my.v2;
}
with str as the std::string member. This writes into your struct, using tab as the first delimiter and then any white-space delimiter will do before the next two integers. (You can force it to use tab).
To read line by line you can either continue reading these, or read the line first into a string then put the string into an istringstream and call the above.
You will need to decide how to handle failed reads. Any failed read above would leave the stream in a failed state.
std::ifstream in("fname");
while(in){
std::string line;
std::getline(in,line);
size_t lasttab=line.find_last_of('\t');
size_t firsttab=line.find_last_of('\t',lasttab-1);
mystruct data;
data.chr=line.substr(0,firsttab).c_str();
data.v1=atoi(line.substr(firsttab,lasttab).c_str());
data.v2=atoi(line.substr(lasttab).c_str());
}
I had some difficulty following some of the suggestions here, so I'm posting a complete example of overloading both input and output operators for a struct over a tab-delimited file. As a bonus, it also takes the input either from stdin or from a file supplied via the command arguments.
I believe this is about as simple as it gets while adhering to the semantics of the operators.
pairwise.h
#ifndef PAIRWISE_VALUE
#define PAIRWISE_VALUE
#include <string>
#include <iostream>
struct PairwiseValue
{
std::string labelA;
std::string labelB;
float value;
};
std::ostream& operator<<(std::ostream& os, const PairwiseValue& p);
std::istream& operator>>(std::istream& is, PairwiseValue& p);
#endif
pairwise.cc
#include "pairwise.h"
std::ostream& operator<<(std::ostream& os, const PairwiseValue& p)
{
os << p.labelA << '\t' << p.labelB << '\t' << p.value << std::endl;
return os;
}
std::istream& operator>>(std::istream& is, PairwiseValue& p)
{
PairwiseValue pv;
if ((is >> pv.labelA >> pv.labelB >> pv.value))
{
p = pv;
}
return is;
}
test.cc
#include <fstream>
#include "pairwise.h"
int main(const int argc, const char* argv[])
{
std::ios_base::sync_with_stdio(false); // disable synch with stdio (enables input buffering)
std::string ifilename;
if (argc == 2)
{
ifilename = argv[1];
}
const bool use_stdin = ifilename.empty();
std::ifstream ifs;
if (!use_stdin)
{
ifs.open(ifilename);
if (!ifs)
{
std::cerr << "Error opening input file: " << ifilename << std::endl;
return 1;
}
}
std::istream& is = ifs.is_open() ? static_cast<std::istream&>(ifs) : std::cin;
PairwiseValue pv;
while (is >> pv)
{
std::cout << pv;
}
return 0;
}
Compiling
g++ -c pairwise.cc test.cc
g++ -o test pairwise.o test.o
Usage
./test myvector.tsv
cat myvector.tsv | ./test