Since std::stringstream is a stzream, and according to the documention here, you can perform any operation a stream supports.
So I expected the following sample to work, but it seems it doesn't. I'm using MingW with gcc 4.8.3.
Variant A:
std::string s;
std::stringstream doc;
doc << "Test " << "String ";
doc << "AnotherString";
doc >> s;
std::cout << s << std::endl;
Variant B:
std::string s;
std::stringstream doc;
doc << "Test ";
doc << "AnotherString";
doc >> s;
std::cout << s << std::endl;
The output of this is only
Test
While I expected that it would concatenate the individual strings until I read from the stream back what I put there.
So what is the approperiate way to concatenate strings? Do I really have to read out each one individually and concatenate them manually, which seems quite awkward to me in C++.
It is putting each of the strings into doc, so that its content is:
Test String AnotherString
Then when you extract using doc >> s, it only reads up to the first whitespace. If you want to get the entire stream as a string, you can call str:
std::cout << doc.str() << std::endl;
It will only read one word till a white-space by using stream >> s. Besides #JosephMansfield's answer of using str(), alternatively you can use getline() (works perfectly if you the string doesn't contains new lines):
getline(doc, s);
Related
I am trying to input data from a text file:
The line format is as follows...
String|String|int double
Example:
Bob|oranges|10 .89
I can get the line in as a string using
Getline(infile, line)
I don't understand how to break the line into the distinct variables from the string variable.
Thanks
for a start you could write some good old fashioned c code using strchr.
Or use string.find / find_first_of if you are using std::String
http://www.cplusplus.com/reference/string/string/find_first_of/
You marked this as C++. So perhaps you should try to use formatted extractors ...
Here is a 'ram' file (works just like a disk file)
std::stringstream ss("Bob|oranges|10 .89");
// this ^^^^^^^^^^^^^^^^^^ puts one line in file
I would use getline for the two strings, with bar terminator
do {
std::string cust;
(void)std::getline(ss, cust, '|'); // read to 1st bar
std::string fruit;
(void)std::getline(ss, fruit, '|'); // read to 2nd bar
Then read the int and float directly:
int count = 0;
float cost;
ss >> count >> cost; // the space char is ignored by formatted extraction
std::cout << "\ncust: " << cust << "\n"
<< " " << count << " " << fruit
<< " at $" << cost
<< " Totals: " << (float(count) * cost) << std::endl;
if(ss.eof()) break;
}while(0);
If you are to handle more lines, you need to find the eoln, and repeat for every record of the above style.
This approach is extremely fragile (any change in format will force a change in your code).
This is just to get your started. It has been my experience that using std::string find and rfind is much less fragile.
Good luck.
I have a stringstream where I need to get the first part out and then get the remainder into a separate string. For example I have the string "This is a car" and I need to end up with 2 strings: a = "This" and b = "is a car".
When I use stringstream to get the first part using <<,then I use the .str() to convert to a string which of course gave me the whole thing "This is a car". How can I get it to play how I want?
string str = "this is a car";
std::stringstream ss;
ss << str;
string a,b;
ss >> a;
getline(ss, b);
EDIT: correction thanks to #Cubbi:
ss >> a >> ws;
EDIT:
This solution can handle newlines in some cases (such as my test cases) but fails in others (such as #rubenvb's example), and I haven't found a clean way to fix it. I think #tacp's solution is better, more robust, and should be accepted.
You can do this: first get the whole string, then get the first word, using substr to get the rest.
stringstream s("This is a car");
string s1 = s.str();
string first;
string second;
s >> first;
second = s1.substr(first.length());
cout << "first part: " << first <<"\ second part: " << second <<endl;
Testing this in gcc 4.5.3 outputs:
first part: This
second part: is a car
You can do a getline on the stream after reading out the first bit....
Another way to do this is with rdbuf:
stringstream s("This is a car");
string first;
stringstream second;
s >> first;
second << s.rdbuf();
cout << "first part: " << first << " second part: " << second.str() << endl;
This may be a good option if you're ultimately going to output the result to a stream instead of a string.
I am using boost::split to parse a data file. The data file contains lines such as the following.
data.txt
1:1~15 ASTKGPSVFPLAPSS SVFPLAPSS -12.6 98.3
The white space between the items are tabs. The code I have to split the above line is as follows.
std::string buf;
/*Assign the line from the file to buf*/
std::vector<std::string> dataLine;
boost::split( dataLine, buf , boost::is_any_of("\t "), boost::token_compress_on); //Split data line
cout << dataLine.size() << endl;
For the above line of code I should get a print out of 5, but I get 6. I have tried to read through the documentation and this solution seems as though it should do what I want, clearly I am missing something. Thanks!
Edit:
Running a forloop as follows on dataLine you get the following.
cout << "****" << endl;
for(int i = 0 ; i < dataLine.size() ; i ++) cout << dataLine[i] << endl;
cout << "****" << endl;
****
1:1~15
ASTKGPSVFPLAPSS
SVFPLAPSS
-12.6
98.3
****
Even though "adjacent separators are merged together", it seems like the trailing delimeters make the problem, since even when they are treated as one, it still is one delimeter.
So your problem cannot be solved with split() alone. But luckily Boost String Algo has trim() and trim_if(), which strip whitespace or delimeters from beginning and end of a string. So just call trim() on buf, like this:
std::string buf = "1:1~15 ASTKGPSVFPLAPSS SVFPLAPSS -12.6 98.3 ";
std::vector<std::string> dataLine;
boost::trim_if(buf, boost::is_any_of("\t ")); // could also use plain boost::trim
boost::split(dataLine, buf, boost::is_any_of("\t "), boost::token_compress_on);
std::cout << out.size() << std::endl;
This question was already asked: boost::split leaves empty tokens at the beginning and end of string - is this desired behaviour?
I would recommend using C++ String Toolkit Library. This library is much faster than Boost in my opinion. I used to use Boost to split (aka tokenize) a line of text but found this library to be much more in line with what I want.
One of the great things about strtk::parse is its conversion of tokens into their final value and checking the number of elements.
you could use it as so:
std::vector<std::string> tokens;
// multiple delimiters should be treated as one
if( !strtk::parse( dataLine, "\t", tokens ) )
{
std::cout << "failed" << std::endl;
}
--- another version
std::string token1;
std::string token2;
std::string token3:
float value1;
float value2;
if( !strtk::parse( dataLine, "\t", token1, token2, token3, value1, value2) )
{
std::cout << "failed" << std::endl;
// fails if the number of elements is not what you want
}
Online documentation for the library: String Tokenizer Documentation
Link to the source code: C++ String Toolkit Library
Leading and trailing whitespace is intentionally left alone by boost::split because it does not know if it is significant or not. The solution is to use boost::trim before calling boost::split.
#include <boost/algorithm/string/trim.hpp>
....
boost::trim(buf);
I'm doing a server application in C++, and it provides an HTML page as response to HTTP requests.
The problem is that, currently, my webpage is written as a constant string in my code, and I insert other strings using << operator and std::stringstream, still during the writing of the string itself. See the example to get it clearer:
std::string first("foo");
std::string second("bar");
std::string third("foobar");
std::stringstream ss;
ss << "<html>\n"
"<head>\n"
"<title>Bitches Brew</title>\n"
"</head>\n"
"<body>\n"
"First string: "
<< first << "\n"
"Second string: "
<< second << "\n"
"Third string: "
<< third << "\n"
"</body>\n"
"</html>";
Happens though I cannot simply stuff the contents in a file, because the data mixed with the HTML structure will change during the execution. This means I can't simply write the entire page in a file, with the string values of first, second, and third, because these values will change dynamically.
For the first request I'd send the page with first = "foo";, whereas in the second request I'd have first = "anything else".
Also, I could simply go back to sscanf/sprintf from stdio.h and insert the text I want -- I'd just have to replace the string gaps with the proper format (%s), read the HTML structure from a file, and insert whatever I wanted.
I'd like to do this in C++, without C library functions, but I couldn't figure out what to use to do this. What would be the C++ standard solution for this?
Standard C++ doesn't have a direct equivalent to (s)printf-like formatting other than (s)printf itself. However, there are plenty of formatting libraries that provide this functionality, like the cppformat library that includes a C++ implementation of Python's str.format and safe printf.
That said, I'd recommend using a template engine instead, see
C++ HTML template framework, templatizing library, HTML generator library .
Or you can always reinvent the wheel and write your own template engine by reading a file and replacing some placeholders with arguments.
What about:
void RenderWebPage(std::stringstream& ss, std::string& first, std::string& second, std::string& third)
{
ss << "<html>\n"
"<head>\n"
"<title>Bitches Brew</title>\n"
"</head>\n"
"<body>\n"
"First string: "
<< first << "\n"
"Second string: "
<< second << "\n"
"Third string: "
<< third << "\n"
"</body>\n"
"</html>";
}
And you can call it like this:
std::stringstream ss;
std::string first("foo");
std::string second("bar");
std::string third("foobar");
RenderWebPage(ss, first, second, third);
first = "anything else";
RenderWebPage(ss, first, second, third);
second = "seconds too";
RenderWebPage(ss, first, second, third);
You can get the desired result like this:
Store your static HTML in a file, with placeholders for the dynamic text
Read the HTML file into a std::string
For each piece of dynamic text, locate its placeholder in the string (std::string::find) and replace the placeholder with the dynamic text (std::string::replace).
Write the modified string to the final destination.
If you don't want to use a framework as other answers (correctly) suggest, I guess you can take inspiration from this little program:
#include <iostream>
#include <map>
using namespace std;
string instantiate_html(string const& templateHTML, map<string, string> const& replacements)
{
string outputHTML = templateHTML;
for (auto& entry : replacements)
{
string placeholder = "<$" + entry.first + "$>";
size_t it = outputHTML.find(placeholder);
if (it != string::npos)
{
outputHTML.replace(it, placeholder.size(), entry.second);
}
}
return outputHTML;
}
int main()
{
map<string, string> replacements;
replacements["name"] = "Mark";
replacements["surname"] = "Brown";
// Normally you would read this string from your template file
string templateHTML = "<html><body><$name$><$surname$></body></html>";
string outputHTML = instantiate_html(templateHTML, replacements);
cout << outputHTML;
return 0;
}
I have following string:
"hw_core_detectionhook::Iocard const*"
I have to get only first part, i.e all text present before space, i.e I need the "hw_core_detectionhook::Iocard" part only.
std::stringstream ss;
ss << "hw_core_detectionhook::Iocard const*";
std::string s;
ss >> s;
std::cout << s;
Output:
hw_core_detectionhook::Iocard
See the complete demo online : http://www.ideone.com/w9l1C
s.substr(0,s.find_first_of(" "));