I have two char* strings and a char* literal that I need to combine into a single std::string. Below is what I am doing. It works, but I don't like the way it looks (3 lines to accomplish it). I am wondering if there is a better way to do it...
std::string strSource = _szImportDirectory;
strSource += "\\";
strSource += _szImportSourceFile;
Thanks for you help!
std::string strSource = std::string(_szImportDirectory) + "\\" + _szImportSourceFile;
Is one obvious way.
Another way is to use std::stringstream:
std::stringstream s;
s << _szImportDirectory << '\\' + _szImportSourceFile;
std::string strSource = s.str()
That's the most flexible and maintainable way to do it but it still requires three lines.
Something like this?
std::string str = std::string(_szImportDirectory).append("\\").append(_szImportSourceFile);
PS: updated with correct code
Related
I want to call a function with an argument, which is a constructed string. For example:
std::string str = "data";
// ...
debug("we have " + str + " and it's good");
ideone link.
As far as I know, it creates a string in the first concatenation, and then creates a new one in the second concatenation, which means two inevitable allocations.
Is the following code more performant?
std::string str = "data";
// ...
debug(std::string("we have ") += str += " and it's good");
Or is the first code being optimized by the compiler to something similar?
I'd like to add a timestamp to the filename in this part of my code:
takeScreenshot( "screenshot.png" );
But all ways of doing this that I've found seem unnecessarily long and complicated. E.g. creating a new string, loading a time struct, converting an element of the time struct to a char array and appending it to the string.
Is there a short way to accomplish this? Most other languages would have some simple solution like:
takeScreenshot( sprintf( "screenshot-%d.png", time() ) );
Is there one in C++? The time format doesn't matter.
Concatenating a string is long and complicated, under the hood.
A nice way is to use std::stringstream which overloads << for concatenation:
std::stringstream ss;
ss << "screenshot-" << time() << ".png";
std::string s = ss.str();
and format time() to personal taste.
You can use stringstream or just use + operator between strings:
takeScreenshot("screenshot-" + time() + ".png");
I'm struggling with the following: I'm reading from an XML file the following std::stringstream
"sigma=0\nreset"
Which after some copying&processing is written to a text-file. And I was hoping for the following
sigma=0
reset
But sadly I only get
sigma=0\nreset
but when I directly stream
out << "sigma=0\nreset"
I get:
sigma=0
reset
I currently suspect that some qualifier of the "\n" is lost during the "copy&processing"... is this possible? How to track down a "\n" in the stream which isn't a linefeed anymore?
Thank you!
It's because the output functions doesn't handle the escape sequences like '\n', it's the compiler that does and then only for literals. The compiler knows nothing of the contents of strings, and so can not do the translation "\n" to newline when inside a string.
You have to parse the string itself, and write out newlines when appropriate.
Assuming that the std::stringstream actually contains what is equivalent to the literal "sigma=0\\nreset" (length = 14 characters) and not "sigma=0\nreset" (length = 13 characters), you'll have to replace it yourself. Doing so is not very difficult, either use boost's replace_all (http://www.boost.org/doc/libs/1_53_0/doc/html/boost/algorithm/replace_all.html), or std::string::find and std::string::replace:
std::stringstream inStream;
inStream.str ("sigma=0\\nreset");
std::string content = inStream.str();
size_t index = content.find("\\n",0);
while(index != std::string::npos)
{
content.replace(index, 2, "\n");
index = content.find("\\n",index);
}
std::cout << content << '\n';
Note: you may want to consider cases when the system end-of-line is something other than "\n"
If the std::stringstream actually contains "sigma=0\nreset", then please post the code that does the copying/processing and the writing to the text file.
I am trying to write some code that changes a string like "/path/file.extension" to another specified extension. I am trying to use boost::xpressive to do so. But, I am having problems. It appears that a garbage character appears in the output:
#include <iostream>
#include <boost/xpressive/xpressive.hpp>
using namespace boost::xpressive;
using namespace std;
int main()
{
std::string str( "xml.xml.xml.xml");
sregex date = sregex::compile( "(\\.*)(\\.xml)$");
std::string format( "\1.zipxml");
std::string str2 = regex_replace( str, date, format );
std::cout << "str = " << str << "\n";
std::cout << "str2 = " << str2 << "\n";
return 0;
}
Now compile and run it:
[bitdiot#kantpute foodir]$ g++ badregex.cpp
[bitdiot#kantpute foodir]$ ./a.out > output
[bitdiot#kantpute foodir]$ less output
[bitdiot#kantpute foodir]$ cat -vte output
str = xml.xml.xml.xml$
str2 = xml.xml.xml^A.zipxml$
In the above example, I redirect output to a file, and use cat to print out the non-printable character. Notice the ctrl-A in the str2.
Anyways, am I using boost libraries incorrectly? Is this a boost bug? Is there another regular expression I can use that can allow me to string replace the ".tail" with some other string? (It's fix in my example.)
thanks.
At least as I'm reading things, the culprit is right here: std::string format( "\1.zipxml");.
You forgot to escape the backslash, so \1 is giving you a control-A. You almost certainly want \\1.
Alternatively (if your compiler is new enough) you could use a raw string instead, so it would be something like: R"(\1.zipxml)", and you wouldn't have to escape your backslashes. I probably wouldn't bother to mention this, except for the fact that if you're writing REs in C++ strings, raw strings are pretty much your new best friend (IMO, anyway).
As Jerry Coffin pointed out to me. It was a stupid mistake on my part.
The errant code is the following:
std::string format( "\1.zipxml");
This should be replaced with:
std::string format( "$1.zipxml");
Thanks for your help everyone.
I've got the following string :
const std::string args = "cmdLine=\"-d ..\\data\\configFile.cfg\" rootDir=\"C:\\abc\\def\""; // please note the space after -d
I'd like to split it into 2 substrings :
std::str1 = "cmdLine=...";
and
std::str2 = "rootDir=...";
using boost/algorithm/string.hpp . I figured, regular expressions would be best for this but unfortunately I have no idea how to construct one therefore I needed to ask the question.
Anyone capable of helping me out with this one?
To solve problem from your question the easiest way is to use strstr to find substring in string, and string::substr to copy substring. But if you really want to use Boost and regular expressions you could make it as in the following sample:
#include <boost/regex.hpp>
...
const std::string args = "cmdLine=\"-d ..\\data\\configFile.cfg\" rootDir=\"C:\\abc\\def\"";
boost::regex exrp( "(cmdLine=.*) (rootDir=.*)" );
boost::match_results<string::const_iterator> what;
if( regex_search( args, what, exrp ) ) {
string str1( what[1].first, what[1].second ); // cmdLine="-d ..\data\configFile.cfg"
string str2( what[2].first, what[2].second ); // rootDir="C:\abc\def"
}
Code samples
char *cstr1 = (char*)args.c_str();
char *cstr2 = strstr(cstr1, "=\""); cstr2 = strstr(cstr2, "=\"); // rootDir="
cstr2 = strrchr(cstr2, ' '); // space between " and rootDir
*cstr2++ = '\0';
//then save to your strings
std::string str1 = cstr1;
std::string str2 = cstr2;
that's all.
Notes:
Above code supports these strings
"cmdLine=\"-d ..\\data\\configFile.cfg\" rootDir=\"C:\\abc\\def\"" or
"ABCwhatever=\"-d ..\\data\\configFile.cfg\" XYZ=\"C:\\abc\\def\""