I have an text file with binary values in n columns and y rows.
I am using getline to extract every row of the binary values and assign them to vectors:
I am using getline to extract every row of a file, where each row consists of a series of '0' or '1' separated by space, and assign them to a vector.
std::vector< std::vector<int> > matrix; // to hold everything.
std::string line;
while(std::getline(file,line))
{
std::stringstream linestream(line);
int a,b,c,d;
linestream >> a >> sep >> b >> sep >> c >> sep >> d;
std::vector <int> vi;
vi.push_back(a);
vi.push_back(b);
vi.push_back(c);
vi.push_back(d);
matrix.push_back(vi);
}
Now the problem is that I do not know in advance how many columns are there in the file. How can I loop through every line until i reach the end of that line?
The obvious way would be something like:
while (linestream >> temp >> sep)
vi.push_back(temp);
Though this may well fail for the last item, which may not be followed by a separator. You have a couple of choices to handle that properly. One would be the typical "loop and a half" idiom. Another would be a locale that treats your separator characters as white space.
When/if you do that, you can/could also use a standard algorithm:
std::copy(std::istream_iterator<int>(linestream),
std::istream_iterator<int>(),
std::back_inserter(vi));
Why not
while (in1 >> i) row.push_back( i );
Which does not require a separator?
check for a new line character (\n). when you find one, you've completed the line/column.
Related
Suppose I'm trying to read from the following input.txt
6 Jonathan Kim Jr
2 Suzie McDonalds
4 Patty
... and I want to store the first integers from every line and the rest of the strings as a string variable. This is what I have tried:
int num;
string name1, name2, name3;
while ( ins >> num >> name1 >> name2 >> name3 )
{
// do things
}
Unfortunately this won't work since line 2 and line 3 only has 2 and 1 strings in a respective order so the loop will terminate at the very first loop.
Is there a way to store the rest of the strings after an integer in a single variable, including the white spaces? For example, string variable name would hold:
"Jonathan Kim Jr" // first loop
"Suzie M" // second loop
"Patty" // third loop
I thought about using getline to achieve this as well, but that would require me to isolate the integers from the string and I was hoping there's a better approach do this. Perhaps using a vector?
By default, the >> operator splits on a space, so you could use that to pull the integer into the variable. You could then use getline to grab the rest of the line, and store that into the variable.
Example (if you are reading from std::cin):
int num;
std::string name;
std::cin >> num;
std::getline(std::cin, name);
Why don't use regular expressions (https://en.wikipedia.org/wiki/Regular_expression) to parse (https://en.cppreference.com/w/cpp/regex) the input? I think an expression something along the line of 2 subexpressions:
'^([0-1]+)\s([A-Za-z0-9_-/s]+)'
The input for the program consists of two parts.
The first line of the input is the number of elements, and the second line is all the elements. This is an example input:
5
1 3 23 4 2
Is there a way to deal with this kind of input without using std::string and parsing it to the vector of ints later?
It sounds like this is for a programming competition or some other similar setup where you can trust that the input is properly formatted. If that's the case, yes, you can do this without buffering things through a std::string. Here's one option:
std::size_t size;
std::cin >> size;
std::vector<int> values;
// Could do values.reserve(size); here if you'd like.
for (std::size_t i = 0; i < size; i++) {
std::size_t value;
std::cin >> value;
values.push_back(value);
}
Note that the stream extraction operator operator >> will use any whitespace character as a delimiter, so the newline after the number of elements and the space characters between the numbers themselves will work great as separators. There's no need to pull the entire second line by itself and then parse it apart.
This does no error-checking, which is a real problem if you can't trust the inputs. But if you can, this should do the trick.
I have an input text file. The first line has two int numbers a and b, and the second line is a string. I want to use formatted input to do file >> a >> b, and then unformatted input to get the characters of the string one by one. In between the two steps, I need to skip over the '\n' character at the end of the first line. I used
while(file.get()<=' ' && !file.eof()); // skip all unprintable chars
if(!file.eof()) file.unget(); // keep the eof sign once triggered
to make the input format more flexible. The user can now separate the numbers a and b from the string using an arbitrary number of empty lines '\n', tab keys '\t', and/or space keys ' ' -- the same freedom he has to separate the numbers a and b. There's even no problem reading in Linux a text file copied from Windows when every end of line now becomes "\r\n".
Is there an ifstream function that does the same thing (skip all chars <=' ' until the next printable char or EOF is reached)? The ignore function does not seem to do that.
Yes, there is: std::ws manipulator. It skips whitespace characters until a non-whitespace is found or end of stream is reached.. It is similar to use of whitespace character in scanf format string.
In fact, it is used by formatted input before actually starting to parse characters.
You can use it like that:
int x;
std::string str;
std::cin >> x >> std::ws;
std::getline(std::cin, str);
//...
//std::vector<int> vec;
for(auto& e: vec) {
std::cin >> e;
}
std::getline(std::cin >> std::ws, str);
Sometimes I use std::stringstream to parse a text file, e.g.
8 9
100 1002 3.345
100 102 2.345
std::stringstream ss(file);
int unused1, unused2, first_useful_value;
ss >> unused1 >> unused2;
ss >> first_useful_value >> ...
now suppose that the first line, i.e.
8 9
are useless values to me and I just need to discard them. I might consider the entire line useless or I might consider some of those values useless.
My question is: is there any way to discard a value of a given type without having to declare useless variables on the stack (either wasteful and less readable)?
You can use std::stringstream::ignore with delimeter \n to skip the first line as follows:
ss.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
LIVE DEMO
or use as delimiter space or what ever separates your values to discard one at a time:
ss.ignore(std::numeric_limits<std::streamsize>::max(), ' '); // delimiter is space
ss.ignore(std::numeric_limits<std::streamsize>::max(), ','); // delimeter is comma
LIVE DEMO
For a small portion of my project, I'm supposed to extract data from a text file using cin which my program will know where to cin from based on command line arguments. My issue is how to extract the four pieces of data and ignore the commas. For example, the .txt file will look like the following
(1,2,3,.)
(2,1,3,#)
(3,1,0,.)
In which case I need to extract the 1, the 2, the 3, and the . for the first line. Then move to the second line. When a blank newline is reached than I can exit the getline() scenario through a while loop.
I know I need to use getline() and I was able to extract the data by using the .at() function of the string generated by getline(). I became confused however when a coordinate such as the 1, the 2, or the 3, could be double digits. When this happened, my previous algorithm didn't work so I feel I'm overthinking things and there should be a simpler way to parse this data.
Thanks!
You can just use the >> operator to a dummy 'char' variable to read in the separators. This assumes you don't care about the 4th token and that it's always a single character:
char ch;
while (ss >> ch)
{
int a,b,c;
ss >> a >> ch >> b >> ch >> c >> ch >> ch >> ch;
}
A simple approach is to use sscanf, pass the string you read from cin to it as the first argument
sscanf(s, "(%d,%d,%d,%c)", &a, &b, &c))
If you want to parse the string from scratch, just focus the pattern.
In this case, the pattern is
'(', number, ',', number, ',', number, ',', char, ')'
So you can locate the three commas, then simply extract three numbers from between them.
A more complicated method is regex.
But C++ doesn't have native support for that (the Boost library does)