ostringstream ss;
ss << "(1,2)\n" << "(1,3)\n" << "(1,4)\n" ;
cout << ss.str();
should print the following:
(1,2)
(1,3)
(1,4)
How could i reverse the output by line so that it prints:
(1,4)
(1,3)
(1,2)
You could use a custom std::streambuf which internally keeps a stack of std::strings and puts them together upon using a str() member. For example:
#include <iostream>
#include <numeric>
#include <streambuf>
#include <string>
#include <vector>
class stackbuf
: public std::streambuf
{
std::vector<std::string> d_lines;
int overflow(int c) {
if (c != std::char_traits<char>::eof()) {
this->d_lines.back().push_back(c);
if (c == '\n') {
this->d_lines.push_back(std::string());
}
}
return std::char_traits<char>::not_eof(c);
}
public:
stackbuf(): d_lines(1) {}
std::string str() const {
return std::accumulate(this->d_lines.rbegin(),
this->d_lines.rend(),
std::string());
}
};
int main()
{
stackbuf sbuf;
std::ostream out(&sbuf);
out << "(1, 2)\n(1, 3)\n(1, 4)\n";
std::cout << sbuf.str();
}
For a real-world application you should, obviously, set up a buffer in the stream buffer to improve the performance. You may also want to create a custom stream directly initializing the stream's stream buffer.
Using your original code with C++98:
ostringstream ss;
ss << "(1,2)\n" << "(1,3)\n" << "(1,4)\n" ;
cout << ss.str();
//assign a string to the contents of the ostringstream:
string rawlines = ss.str();
//now create an input stringstream with the value of the rawlines
istringstream iss(rawlines);
string temp;//just a temporary object used for storage
vector<string> lines;//this is where your lines will be held
//now iterate over the stream and store the contents into the vector `lines`:
while(getline(iss, temp)) {
lines.push_back(temp);
}
//now reverse the contents:
reverse(lines.begin(), lines.end());
//see what's inside:
for (vector<string>::const_iterator it = lines.begin(); it != lines.end(); ++it) {
cout << *it << endl;
}
This will print:
(1,4)
(1,3)
(1,2)
As desired
NOTE: This strips the newlines from the the original string.
And, this requires:
//for `getline`:
#include <cstdlib>
//for `reverse`:
#include <algorithm>
//for `string`:
#include <string>
//for `vector`:
#include <vector>
You can use reverse iterators:
std::ostringstream ss{ "(1,2)\n(1,3)\n(1,4)\n" };
std::string str = ss.str();
std::copy( str.rbegin(), str.rend(),
std::ostream_iterator<std::string>{std::cout, "\n"} );
This code will require:
#include <iostream>
#include <algorithm>
#include <iterator>
#include <string>
#include <sstream>
and basic C++11 support.
This would be the classic way, best leveraging the standard C++ library.
#include <iostream>
#include <sstream>
#include <stack>
#include <string>
using namespace std;
int main(int argv, char* arv[])
{
ostringstream oss;
oss << "(1,2)\n" << "(1,3)\n" << "(1,4)\n" ;
cout << oss.str() << "----------\n";
// Reverse lines
// Fill an istringstream with buffer contents of the ostringstream
istringstream iss(oss.str());
stack<string> stk;
while (iss) {
string s;
if (!getline(iss, s)) break; // Read a line
s += '\n'; // Put back newline stripped by readline
stk.push(s); // Push line to stack
}
oss.clear(); // Clear state of the ostringstream
oss.str(""); // Clear contents of the ostringstream for reuse
while (!stk.empty()) {
string s;
s = stk.top(); // Get top of stack
oss << s; // Output it to the ostringstream
stk.pop(); // Pop and throw away top of stack
}
cout << oss.str();
return 0;
}
Related
The next code returns an empty string in ss:
#include <string>
#include <iostream>
#include <sstream>
int main () {
std::ostringstream oss;
oss << "Text";
std::stringstream ss;
ss.basic_ios<char>::rdbuf(oss.rdbuf());
std::cout << ss.str() << "\n";
return 0;
}
How can I return from ss the text introduced in oss? I'm mainly interested in converting std::ostringstream into std::stringstream.
You could make use of the protected std::streambuf::swap member function that exchanges the contents of the stream buffer with those of another
To get access to it, you'll need a derived class:
#include <iostream>
#include <sstream>
struct swapper : std::streambuf {
using std::streambuf::streambuf;
void swap(std::streambuf& rhs) { // public proxy for protected swap
std::streambuf::swap(rhs);
}
};
// casting
void swapbuf(std::ostream& a, std::ostream& b) {
static_cast<swapper*>(a.rdbuf())->swap(*b.rdbuf());
}
int main () {
std::ostringstream oss;
oss << "Text";
std::stringstream ss;
swapbuf(oss, ss);
std::cout << "ss: " << ss.str() << "\n"; // prints Text
}
Following comments from #NathanOliver, I decided to convert std::ostringstream into std::stringstream by using str():
#include <string>
#include <iostream>
#include <sstream>
int main () {
std::ostringstream oss;
oss << "Text";
std::stringstream ss;
ss << oss.str();
std::cout << ss.str() << "\n";
return 0;
}
I'm reading some network data into a stringstream as an input_buffer.
The data is ASCII lines separated by a LF char.
The input_buffer may be in a state where there is only a partial line in it.
I'm trying to call getline (), but only when there actually is a new newline char in the stringstream. In other words it should extract completed lines, but leave a partial line in the buffer.
Here is a MVCE:
#include <string>
#include <sstream>
#include <iostream>
int
main (void)
{
std::stringstream input_buffer;
input_buffer << "test123\nOK\n";
while (input_buffer.str ().find ('\n') != std::string::npos)
{
std::string line;
std::getline (input_buffer, line, '\n');
std::cout << "input_buffer.str ().size: " << input_buffer.str ().size () << "\n";
std::cout << "line: " << line << "\n";
}
return 0;
}
It currently does not terminate, here is a fragment of the output:
input_buffer.str ().size: 11
line: test123
input_buffer.str ().size: 11
line: OK
input_buffer.str ().size: 11
line:
input_buffer.str ().size: 11
...
How can I read a line from a stringstream only if it contains any newline?
Edit: For clarification here is another code sample with partial input:
#include <string>
#include <sstream>
#include <iostream>
#include <vector>
void
extract_complete_lines_1 (std::stringstream &input_buffer, std::vector<std::string> &lines)
{
while (input_buffer.str ().find ('\n') != std::string::npos)
{
std::string line;
std::getline (input_buffer, line, '\n');
lines.push_back (line);
}
}
void
print_lines (const std::vector<std::string> &v)
{
for (auto l : v)
{
std::cout << l << '\n';
}
}
int
main (void)
{
std::vector<std::string> lines;
std::stringstream input_buffer {"test123\nOK\npartial line"};
extract_complete_lines_1 (input_buffer, lines);
print_lines (lines);
return 0;
}
This should print "test123" and "OK", but not "partial line".
As mentioned here, you could override the underflow function of the buffer so that it will refill using a function that you can specify.
Here is an example adapted from here:
#include <iostream>
#include <sstream>
#include <string>
class Mybuf : public std::streambuf {
std::string line{};
char ch{}; // single-byte buffer
protected:
int underflow() override {
if(line.empty()) {
std::cout << "Please enter a line of text for the stream: ";
getline(std::cin, line);
line.push_back('\n');
}
ch = line[0];
line.erase(0, 1);
setg(&ch, &ch, &ch + 1); // make one read position available
return ch;
}
public:
Mybuf(std::string line) : line{line} {};
};
class mystream : public std::istringstream {
Mybuf mybuf;
public:
mystream(std::string line) : std::istringstream{}, mybuf{line}
{
static_cast<std::istream&>(*this).rdbuf(&mybuf);
}
};
int main()
{
mystream ms{"The first line.\nThe second line.\nA partial line"};
for(std::string line{}; std::getline(ms, line); )
std::cout << "line: " << line << "\n";
}
Output:
line: The first line.
line: The second line.
Please enter a line of text for the stream: Here is more!
line: A partial lineHere is more!
Please enter a line of text for the stream:
I think that it's not easily possible with std::stringstream. I tried to manipulate the stream position with tellg () and seekg (), but they don't behave like I expected.
I have found a solution using a std::vector<char> as a buffer:
#include <string>
#include <sstream>
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
void
extract_complete_lines (std::vector<char> &buf, std::vector<std::string> &lines)
{
auto pos = std::end (buf);
while ((pos = std::find (std::begin (buf), std::end (buf), '\n')) != std::end (buf))
{
std::string line (std::begin (buf), pos);
buf.erase (std::begin(buf), pos + 1);
lines.push_back (line);
}
}
void
print_lines (const std::vector<std::string> &v)
{
for (auto l : v)
{
std::cout << l << '\n';
}
}
int
main (void)
{
std::vector<std::string> lines;
const std::string test_input = "test123\nOK\npartial line";
std::vector<char> input_buffer {std::begin (test_input), std::end (test_input)};
extract_complete_lines_1 (input_buffer, lines);
print_lines (lines);
return 0;
}
It prints the first two lines as expected and the "partial line" is left in the vector.
Or even better, a std::vector<char> is not too different from a std::string:
#include <string>
#include <sstream>
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
void
extract_complete_lines (std::string &buf, std::vector<std::string> &lines)
{
std::string::size_type pos;
while ((pos = buf.find ('\n')) != std::string::npos)
{
lines.push_back (buf.substr (0, pos));
buf.erase (0, pos + 1);
}
}
void
print_lines (const std::vector<std::string> &v)
{
for (auto l : v)
{
std::cout << l << '\n';
}
}
int
main (void)
{
std::vector<std::string> lines;
std::string input_buffer = "test123\nOK\npartial line";
extract_complete_lines (input_buffer, lines);
print_lines (lines);
return 0;
}
I have the following struct:
struct msg_latency{
double time;
string data;
};
I have a vector of strings which contains strings like:
"2344.5435345 hello world\n:"
I have to iterate the vector of the strings and convert each string to msg_latency struct.
vector<msg_latency> vec_msg
convert_str2struct(vector<string> str_vec, vector<msg_latency> msg_vec)
{
vector<string>::iterator msg_it;
for(msg_it=str_vec.begin(); msg_it!= str_vec.end(); ++msg_it)
{
///TODO
}
}
While in the todo I want to write something like:
msg_vec[i].time= *msg_it.substr(0, *msg_it.find(" "));
msg_vec[i].data= *msg_it;
How can I initialize the msg_vec as I describred above?
Can I do something like (in the TODO):
msg_vec.push_back({*msg_it.substr(0, *msg_it.find(" ")), *msg_it})?
As suggested in comments, this is an ideal application for std::transform and std::istringstream.
If I understand your string format you can use std::getline to read the remaining part of string after reading the double:
#include <string>
#include <vector>
#include <sstream>
#include <algorithm>
#include <iostream>
msg_latency
convert(const std::string& str) {
msg_latency msg;
std::istringstream ss(str);
ss >> msg.time >> std::ws; // read double and whitespace separator
getline(ss, msg.data); // read the rest of the string
return msg;
}
std::vector<msg_latency>
convert_str2struct(const std::vector<std::string>& str_vec) {
std::vector<msg_latency> ret(str_vec.size());
std::transform(str_vec.begin(), str_vec.end(), ret.begin(), convert);
return ret;
}
int main() {
auto vec_str = std::vector<std::string>{"2344.5435345 hello world\n", "42.0 foo\n"};
auto vec_msg = convert_str2struct(vec_str);
for (const auto& msg : vec_msg) {
std::cout << msg.time << "\n";
std::cout << msg.data << "\n";
std::cout << "\n";
}
}
Live demo.
Example ABC.txt
10.f 30.2f 20.f
I want to retrieve those information and store inside my array. However i am unsure how to do it.
I dont understand what is
Then (if good), it calls num_get::get (using the stream's selected locale) to perform both the extraction and the parsing operations, adjusting the stream's internal state flags accordingly. Finally, it destroys the sentry object before returning.
std::fstream filestr("ABC.txt", std::fstream::in);
if(!filestr.good()) //Logical error on i/o operation
{
//Unable to process
filestr.close();
return;
}
unsigned index= 0;
unsigned count= 0;
while(filestr.good())
{
float buffer= 0.f;
filestr >> std::skipws >> buffer;
score[index]= buffer;
++index;
}
filestr.close();
There are a number of ways to do this. One way is using stringstreams, in combination with vectors and strings:
#include <fstream>
#include <iostream>
#include <string>
#include <cstdlib>
#include <sstream>
#include <vector>
using namespace std;
int main() {
std::ifstream filestr("C:\\nums.txt", std::fstream::in);
std::vector<double> numbers;
if (!(filestr.good())) {
std::cout << "BAD FILE" << std::endl;
exit(0);
}
else {
std::string temp;
double d = 0.0;
while(std::getline(filestr, temp)) {
std::istringstream iss(temp);
while(std::getline(iss, temp, ' ')) {
std::istringstream ist(temp);
ist >> f;
numbers.push_back(f);
}
}
}
//see that the vector has information in it
for (int i = 0; i < numbers.size(); i++) {
std::cout << numbers[i] << std::endl;
}
filestr.close();
return 0;
}
One thing to note is that you could also use iterators here, but that's something you could implement for yourself.
Super simple with istream_iterator. There is only one tricky bit in the code below. The vector constructor call needs an extra set of parens around the first argument to avoid the Most Vexing Parse.
#include <fstream>
#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
using namespace std;
int
main (int argc, char** argv)
{
for (int i = 1; i < argc; ++i) {
ifstream in (argv[i]);
if (!in) {
cerr << "Failed to open " << argv[i] << endl;
continue;
}
vector<double> nums ((istream_iterator<double> (in)), istream_iterator<double> ());
copy (nums.begin (), nums.end (), ostream_iterator<double> (cout, "\n"));
}
return 0;
}
I can get getline() to work with cin (getline(cin,line)), but when I open a stream, it won't read the line from the file. The file contains a list of elements from the periodic table.
for Example:
H
He
O
etc...
EDIT:
However, when I try to cout the newly read line, it doesn't put it into var symbol at the line:
cout << "symbol: " << symbol << endl;
It doesn't give me anything out, but it should return the first element (H).
#include <fstream>
#include <iostream>
#include <vector>
#include <string>
using namespace std;
void print(vector <string> x)
{
cout << "list of elements:" << endl;
for (int i = 0; i < x.size(); ++i)
{
cout << x[i] << endl;
}
}
int main(int argc, char** argv)
{
string symbol;
vector <string> elementlist;
ifstream readin;
readin.open("Elements.txt");
getline(readin,symbol);
cout << "symbol: " << symbol << endl;
while (!readin.good())
{
elementlist.push_back(symbol);
getline(readin,symbol);
}
print (elementlist);
return 0;
}
I'd do it something like this:
#include <string>
#include <iostream>
#include <fstream>
#include <vector>
#include <iterator>
class line {
std::string data;
public:
friend std::istream &operator>>(std::istream &is, line &l) {
std::getline(is, l.data);
return is;
}
operator std::string() const { return data; }
};
int main() {
std::ifstream readin("Elements.txt");
// Initialize vector from data in stream:
//
std::vector<std::string>
element_list((std::istream_iterator<line>(readin)),
std::istream_iterator<line>());
// write data from vector to cout:
//
std::copy(element_list.begin(), element_list.end(),
std::ostream_iterator<std::string>(std::cout, "\n"));
return 0;
}
As I stated in my comment, your loop condition is wrong.
while (!readin.good())
{
elementlist.push_back(symbol);
getline(readin,symbol);
}
As it turns out, you want to loop using the condition readin.good(). Since !readin.good() will evaluate to false, you never actually enter the loop.