Weird behaviour of stringstream? - c++11

I am not able to understand why after reaching the last word it doesn't output blank or null character or garbage value or anything else . Why >> doesn't has any impact whatsoever after finishing the string .
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
using namespace std;
int main()
{
stringstream ss("I am going to goa for"); // Used for breaking words
string word; // To store individual words
while (ss >> word)
cout<<word<<"\n";
ss >> word;
cout<<word<<endl;
ss >> word;
cout<<word<<endl;
ss >> word;
cout<<word<<endl;
}
OUTPUT:
I
am
going
to
goa
for
for
for
for

When >> reaches the end of the string, the failbit is set and it stops reading further.
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
using namespace std;
int main()
{
stringstream ss("I am going to goa for"); // Used for breaking words
string word; // To store individual words
while (ss >> word)
cout<<word<<"\n";
word = "END";
ss >> word;
cout<<word<<endl;
ss >> word;
cout<<word<<endl;
ss >> word;
cout<<word<<endl;
}
You are seeing the for because that is what stored in it. Change it to something else you will find that it doesn't read from the stringstream till failbit is cleared.
The output is:
I
am
going
to
goa
for
END
END
END
Refer stringstream for more details.

Before every cout << word << endl; line you should add if(!ss.fail()) to check no error has occurred in the stringstream following the read attempt.

Related

How would I write a program that reads from a standard input and outputs only 6 characters to a line?

For example if the input was:
My name is Alex and
I also love coding
The correct output should be:
1:My nam
1:e is A
1:lex an
1:d
2:I also
2: love
2:coding
So far I have this
int main () {
string i;
i.substr(0,6);
while (getline(cin, i)) {
cout << i << endl;
}
}
Using ranges, what you ask is almost as easy as
auto result = view | split('\n') | transform(chunk(6));
where view represents somehow the input, | split('\n') splits that input in several lines, and | transform(chunk(6)) transforms each line by splitting it in chunks of 6 chars. The result is therefore a "range of ranges of chunks", on which you can loop with a double nested for.
Here's a full example:
#include <iostream>
#include <sstream>
#include <string>
#include <fstream>
#include <range/v3/range/conversion.hpp>
#include <range/v3/view/chunk.hpp>
#include <range/v3/view/istream.hpp>
#include <range/v3/view/split.hpp>
#include <range/v3/view/transform.hpp>
// Comment/uncomment the line below
//#define FROM_FILE
using namespace ranges;
using namespace ranges::views;
int main() {
// prepare a path-to-file or string buffer
#ifdef FROM_FILE
std::string path_to_file{"/path/to/file"};
#else
std::basic_stringbuf<char> strbuf{"My name is Alex and\nI also love coding"};
#endif
// generate an input stream from the file or the string buffer
#ifdef FROM_FILE
std::ifstream is(path_to_file);
#else
std::istream is(&strbuf);
#endif
// prevent the stream from skipping whitespaces
is >> std::noskipws;
// generate a range view on the stream
ranges::istream_view<char> view(is);
// manipulate the view
auto out_lines = view | split('\n') // split at line breaks
| transform(chunk(6)); // split each in chunks of 6
// output
int index{};
for (auto line : out_lines) {
++index;
for (auto chunk_of_6 : line) {
std::cout << index << ':'
<< (chunk_of_6 | to<std::string>)
<< std::endl;
}
}
}
First I suggest that you give your variables meaningful names. i isn't good for a variable you use to read lines from std::cin. I've changed that name to line in my example below.
You are on the right track with i.substr(0,6); but you've placed it outside of the loop where i is empty - and you don't print it.
You are also supposed to prepend each line with the line number but that part is completely missing.
You have also missed that you should print the next 6 characters of the read line on the next line until you've printed everything that you read.
Here's an example how that could be fixed:
#include <iostream>
#include <string>
int main() {
unsigned max_len = 6;
std::string line;
for(unsigned line_number = 1; std::getline(std::cin, line); ++line_number) {
// loop until the read line is empty:
while(!line.empty()) {
// print max `max_len` characters and prepend it with the line number:
std::cout << line_number << ':' << line.substr(0, max_len) << '\n';
// if the line was longer than `max_len` chars, remove the first
// `max_len` chars:
if(line.size() > max_len) {
line = line.substr(max_len);
} else { // otherwise, make it empty
line.clear();
}
}
}
}

How to convert boost::posix_time::ptime to YYMMDDHHMM?

I am trying to convert boost::posix_time::ptime to YYMMDDHHMM format string. How to accomplish this?
Related: How to convert a boost::ptime to string
#include <iostream>
#include <cstdlib>
#include <string>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/format.hpp>
int main()
{
std::string submitDateString = "20190911T235959";
boost::posix_time::ptime submitPtime = boost::posix_time::from_iso_string( submitDateString );
// Use a facet to display time in a custom format (only hour and minutes).
std::stringstream sstream;
boost::posix_time::time_facet* facet = new boost::posix_time::time_facet();
facet->format("%y%m%d%H%M");
sstream.imbue(std::locale(std::locale::classic(), facet));
sstream << submitPtime;
std::cout << "submit date:" << sstream.str( ) << std::endl;
}

How to Convert Custom string to ptime using boost

I have a string "2018Jan23T181138.65498648" which I need to convert to ptime. I have used below code but seems it is not working. Any idea what I am doing wrong here.
boost::posix_time::ptime pt;
std::istringstream is("2018Jan23T181138.65498648");
is.imbue(std::locale(std::locale::classic(), new boost::posix_time::time_input_facet("%Y%m%dT%H%M%S.%f")));
is >> pt;
std::cout << pt;
You need to at least match the format string to reflect the input format.
"Jan" is not a valid match for %Y%m%d (which would expect 20180123 instead). Likewise, %S.%f is a format string that might work for formatting¹, but to parse the seconds with fractions, the docs show to use %s
Live On Coliru
#include <boost/date_time.hpp>
#include <boost/date_time/posix_time/posix_time_io.hpp>
#include <sstream>
#include <iostream>
int main() {
boost::posix_time::ptime pt;
std::istringstream is("2018Jan23T181138.65498648");
is.imbue(std::locale(std::locale::classic(), new boost::posix_time::time_input_facet("%Y%b%dT%H%M%s")));
if (is >> pt) {
std::cout << pt << "\n";
} else {
std::cout << "unparsed\n";
}
}
Prints
2018-Jan-23 18:11:38.654986
¹ haven't tested it for output formatting

Move or swap a stringstream

I want to move a stringstream, in the real world application I have some stringstream class data member, which I want to reuse for different string's during operation.
stringstream does not have a copy-assignment or copy constructor, which makes sense. However, according to cppreference.com and cplusplus.com std::stringstream should have a move assignment and swap operation defined. I tried both, and both fail.
Move assignment
#include <string> // std::string
#include <iostream> // std::cout
#include <sstream> // std::stringstream
int main () {
std::stringstream stream("1234");
//stream = std::move(std::stringstream("5678"));
stream.operator=(std::move(std::stringstream("5678")));
//stream.operator=(std::stringstream("5678"));
return 0;
}
source: http://ideone.com/Izyanb
prog.cpp:11:56: error: use of deleted function ‘std::basic_stringstream<char>& std::basic_stringstream<char>::operator=(const std::basic_stringstream<char>&)’
stream.operator=(std::move(std::stringstream("5678")));
The compiler states that there is no copy assignment for all three statements, which is true. However, I fail to see why it is not using the move-assignment, especially since std::move is supposed to return a rvalue reference. Stringstream should have a move assignment, as shown here: http://en.cppreference.com/w/cpp/io/basic_stringstream/operator%3D
PS: I'm working with c++11, hence rvalue-references are part of the 'world'.
Swap
This I found really strange, I copied example code from cplusplus.com and it failed:
// swapping stringstream objects
#include <string> // std::string
#include <iostream> // std::cout
#include <sstream> // std::stringstream
int main () {
std::stringstream foo;
std::stringstream bar;
foo << 100;
bar << 200;
foo.swap(bar);
int val;
foo >> val; std::cout << "foo: " << val << '\n';
bar >> val; std::cout << "bar: " << val << '\n';
return 0;
}
source: http://ideone.com/NI0xMS
cplusplus.com source: http://www.cplusplus.com/reference/sstream/stringstream/swap/
prog.cpp: In function ‘int main()’:
prog.cpp:14:7: error: ‘std::stringstream’ has no member named ‘swap’
foo.swap(bar);
What am I missing? Why can't I move or swap a stringstream? How should I swap or move a stringstream?
This is a missing feature on GCC : see bug 54316 , it has been fixed (you can thank Jonathan Wakely) for the next versions (gcc 5)
Clang with libc++ compiles this code :
int main () {
std::stringstream stream("1234");
std::stringstream stream2 = std::move(std::stringstream("5678"));
return 0;
}
Live demo
And it also compiles the example with std::stringstream::swap
I have an alternative to moving or swapping, one can also clear and set a stringstream to a new string:
#include <string> // std::string
#include <iostream> // std::cout
#include <sstream> // std::stringstream
int main () {
std::stringstream ss("1234");
ss.clear();
ss.str("5678");
int val;
ss >> val; std::cout << "val: " << val << '\n';
return 0;
}
It's a clean work around that does not require one to refactor code, except for the localized section where the swap is changed to a clear() and str().

Why won't this program work in release mode?

#include <iostream>
#include <fstream>
#include <stdlib.h> // includes the "atoi" function
#include <string>
using namespace std;
#include <sstream>;
int main()
{
std::fstream f;
f.open("file.in", std::fstream::in);
// read data
int count = 0;
std::string line = "";
getline( f, line, '\n' );
count = atoi( line.c_str() );
f.close();
f.open("file.in", std::fstream::out | std::fstream::trunc);
// write data
++count;
f << count << endl;
f.close();
return 0;
}
This works in debug mode in Visual Studio but when I run it as an application it doesn't work. I've initialized all variables so I'm not sure what else to check.
This line
f.open("file.in", std::fstream::in);
Make sure file.in is in \bin\release
I also advice your to use try/catch statements and print your errors

Resources