library
#include <sstream>
The stringstream class is extremely useful in parsing contest input. It associates a string object with a stream allowing you to read from the string as if it were a stream (like cin).
The basic methods for stringstream are:
- clear () -- clears the error bits in the stringstream object so that you can use it again. You need to call this each time you start parsing a new string with the stringstream object. If you don't, the object could still be in a bad sate and you may not be able to read anything from the stringstream (even if you change its associated string)..
- str () -- returns the string associated with the stringstream object..
- str (s) -- associates the string s to the stringstream object...
- operator << -- add a string to the stringstream object...
- operator >> -- read something from the stringstream object...
As an example, suppose you were told that each test case will be a single line of input with a series of numbers on it. You can't use a bunch of cin's to read the numbers because you don't know how many of them there are. You have to read off the line using getline and then parse the input line. One way would be to scan through the input line looking for spaces, call the substr method of the string class to get the substring for each number, convert it to a C string (the member method c_str()) and then call atoi on that. A far easier way is to use stringstream like this:
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int
main (void)
{
stringstream ss;
int foo;
string inp;
while (getline (cin, inp))
{
ss.clear ();
ss.str ("");
ss << inp;
while (ss >> foo)
{
cout << foo << endl;
}
}
return 0;
}
Here's a more difficult example. Suppose your input is a series of pairs of the form (int,str). Pairs are separated in the input by spaces. If there are no embedded spaces in a given pair, you can read and parse them by:
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int
main (void)
{
stringstream ss;
string inp, w;
int num;
char ch;
while (cin >> inp) {
inp.resize (inp.size () - 1);
ss.clear ();
ss.str ("");
ss << inp;
ss >> ch >> num >> ch >> w;
cout << num << " <--> " << w << endl;
}
return 0;
}
Note in the above examples that clear() and str ("") were always called before using the stringstream object. These two method calls are needed to reset the internal state of the stringstream object.
clear() is needed to reset the internal error flags. If this is not called, the stringstream object may think it's in an error state (such as EOF), even if the underlying string has been changed.
str ("") is needed to clear out the old string. By calling the stream insertion operator, you are adding to the internal string kept by the stringstream object. This feature is useful if you are building up a string from variables and other strings, but can cause your programs to reparse old data.
You can think of a stringstream as a file loaded into something resembling a string, or alternatively, as a sort of string that you can write to and read from like a file. It's not exactly either of those things, but read on and it should become clearer...
A stringstream works essentially the same as an input/output file stream. You need the preprocessor directive #include <sstream>, declare a stringstream just like an fstream, for example
stringstream ss;
and, like an fstream or cout, you can write to it:
ss << myString; or
ss << myCstring; or
ss << myInt;, or float, or double, etc.
and you can read from it:
ss >> myChar; or
ss >> myCstring; or
ss >> myInt; This is also an easy way to convert strings of digits into ints, floats or doubles.
You can get the entire contents of the stringstream as a single C++ string:
string s = ss.str();
And it also inherits many other members from istream and ostream like get, getline, read, write, put, ... In this code I used the stringstream as an intermediate step between an input (text) file and an int array to help deal with the fact that the data within each line of the file was separated by commas, but the lines are separated only by newlines.
Following is a sample program using a stringstream to read numbers from a csv file named "input.txt" into a 6 row by 5 column int array and then prints the array.
It can take data from an input (text) file that looks like this:
and this is what ends up in the array:
It uses both forms of the istream getline member. Both of them take characters from the stream, copy them into a char array and terminate them with a '\0'.
The first one reads up to n-1 characters or until it reaches a newline or eof:
istream& getline (char* s, streamsize n );
The second one reads up to n-1 characters or until it reaches the character specified as 'delim' or eof:
istream& getline (char* s, streamsize n, char delim );
08 | const int BUFFSIZE = 80; |
11 | int array[ROWS][COLS]; |
13 | ifstream infile( "input.txt" ); |
15 | for ( int row = 0; row < ROWS; ++row ) { |
18 | infile. getline ( buff, BUFFSIZE ); |
21 | for ( int col = 0; col < COLS; ++col ) { |
29 | ss. getline ( buff, 6, ',' ); |
33 | array[row][col] = atoi ( buff ); |
44 | for ( int row = 0; row < ROWS; ++row ) { |
45 | for ( int col = 0; col < COLS; ++col ) { |
46 | cout << array[row][col] << " " ; |
The above code was set up explicitly to load data into a 6x5 array because that's what a particular application required, but it can be easily modified to read an entire input file of indeterminate length using a while loop, i.e.
while( infile.getline( buff, 50 ) ) , containing lines with any number of comma-separated values (as long as a big enough buffer is provided). Here's an example of that (it only prints the first 10 columns of the first 10 rows of the array so as not to fill your screen with 0's:
08 | const int BUFFSIZE = 80; |
12 | int array[ROWS][COLS] = {0}; |
15 | ifstream infile( "input.txt" ); |
25 | while ( infile. getline ( buff, BUFFSIZE ) && row < ROWS ) { |
39 | while ( ss. getline ( buff, 10, ',' ) && col < COLS ) { |
43 | array[row][col] = atoi ( buff ); |
56 | for ( int _row = 0; _row < 10; ++_row ) { |
57 | for ( int _col = 0; _col < 10; ++_col ) { |
58 | cout << array[_row][_col] << " " ; |
....
No comments:
Post a Comment