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
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]+)'
I am trying to read the last integer from an input such as-
100 121 13 ... 7 11 81
I'm only interested in the last integer and hence want to ignore all
previous integers.
I thought of using cin.ignore but that won't work here due to
unknown integers (100 is of 3 digits, while 13 is of 2 digits & so on)
I can input integer by integer using a loop and do nothing with them. Is there a better way?
It all depends on the use case that you have.
Reading a none specified number of integers from std::cin is not as easy at it may seem. Because, in contrast to reading from a file, you will not have an EOF condition. If you would read from a file stream, then it would be very simple.
int value{};
while (fileStream >> value)
;
If you are using std::cin you could try pressing CTRL-D or CTRL-Z or whatever works on your terminal to produce an EOF (End Of File) condition. But usually the approach is to use std::getline to read a complete line until the user presses enter, then put this line into a std::istringstream and extract from there.
Insofar, one answer given below is not that good.
So, next solution:
std::string line{};
std::getline(std::cin, line);
std::istringstream iss{line};
int value{};
while (iss >> value)
;
You were asking
Is there a better way?
That also depends a little. If you are just reading some integers, then please go with above approach. If you would have many many values, then you would maybe waste time by unnecessarily converting many substrings to integers and loose time.
Then, it would be better, to first read the complete string, then use rfind to find the last space in the string and use std::stoi to convert the last substring to an integer.
Caveat: In this case you must be sure (or check with more lines of code) that there are no white space at the end and the last substring is really a number. That is a lot of string/character fiddling, which can most probably avoided.
So, I would recommend the getline-stringstream approach.
You can try this simple solution for dynamically ignoring rest of the values except the last given in this problem as shown:
int count = 0;
int values, lastValue; // lastValue used for future use
std::cout << "Enter your input: ";
while (std::cin >> values) {
lastValue = values; // must be used, otherwise values = 0 when loop ends
count++;
}
std::cout << lastValue; // prints
Note: A character must be required to stop the while(), hence it's better put a . at last.
Output example
Enter your input: 3 2 4 5 6 7.
7
Try this:
for( int i=0; i<nums_to_ignore; i++) {
int ignored;
std::cin >> ignored;
}
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);
I have a text file with lines of text that have a string another string followed by up to 4 integers,
ex:
clear "clear water.png" 5 7
wet "wet water.png" 9 5 33 17
soft "soft rain falling.png"
The only way I see it is:
read until space is found
set string to wet
read until double quote
read until second double quote
set second string to wet water.png
while not end of line
read until space
put string through string stream
push resulting integer into vector of int
Is there a better way to do this?
Thanks
This is the sort of task for which scanf and company truly shine.
char first_string[33], second_string[129];
sscanf(input_string,
"%32s%*[^\"]%*c%128[^\"]%*c %d %d %d %d",
first_string,
second_string,
&first_int,
&second_int,
&third_int,
&fourth_int);
You probably want to do that in an if statement so you can test the return value, to tell you how many of those fields converted (e.g., so you know how many integers you read at the end).
Edit: perhaps some explanation would be helpful. Let's dissect that:
%32s reads a string to the first white-space (or 32 characters, whichever comes first).
%*[^\"] ignores input up to the first ".
%*c ignores one more byte of input (the quote itself)
%128[^\"] reads the string in the quote (i.e., up to the next quote character).
%*c Ignores the closing quote
%d Reads an int (which we've done four times).
The space before each %d is really unnecessary -- it'll skip whitespace, but without the space, %d will skip leading whitespace anyway. I've included them purely to make it a little more readable.
Ugly, with no error-checking, but no dependencies on any non-standard libraries:
string s;
while(getline(fin, s))
{
string word, quoted_string;
vector<int> vec;
istringstream line(s);
line >> word;
line.ignore(numeric_limits<streamsize>::max(), '"');
getline(line, quoted_string, '"');
int n;
while(line >> n) vec.push_back(n);
// do something with word, quoted_string and vec...
}
Depending on the restrictions of the input strings you could trying splitting on double-quote then splitting on space.
Yes
Use getline to read one line at a time. Parse the lines using a regular expression library.
I have a text file like this :
Sting Another string 0 12 0 5 3 8
Sting Another string 8 13 2 0 6 11
And I want to count how many numbers are there. I think my best bet is to use while type cycle with a condition to end counting then another line starts but I do not know how to stop reading at the end of a line.
Thanks for your help in advance ;)
Split your input stream into lines
std::string line;
while (std::getline(input, line))
{
// process each line here
}
To split a line into words, use a stringstream:
std::istringstream linestream(line); // #include <sstream>
std::string word;
while (linestream >> word)
{
// process word
}
You can repeat this for each word to decide whether it contains a number. Since you didn't specify whether your numbers are integer or non-integers, I assume int:
std::istringstream wordstream(word);
int number;
if (wordstream >> number)
{
// process the number (count, store or whatever)
}
Disclaimer: This approach is not perfect. It will detect "numbers" at the beginning of words like 123abc, it will also allow an input format like string 123 string. Also this approach is not very efficient.
Why don't you use a getline()?
End of Line is represented by '\n' character.
Put a condition in your while loop to end when it encounters '\n'