Reputation: 43
I have one chance to define the string, lets say
string s = "abc\"def\\hhh\"i";
After this definition, I want to output (using ofstream to write to a text file) two versions of this string afterwards. The first one is the output of s
by default:
abc"def\hhh"i
The second one I want is:
abc\"def\\hhh\"i
I am writing a sort of "recursive" definition, defining another string with extra escape characters is not a solution. I also looked up raw string, but it can only output the second not the first, and it is a feature for c++11, which is too new for some computers to compile.
How can I output the second version of the string without using c++11? If I have to use c++11, how to avoid defining the string twice?
Upvotes: 4
Views: 135
Reputation: 27756
I tend to write something like this as template with range input and iterator output. This provides much flexibility as you can output to a stream, another string or anything else that you could wrap into an output iterator, all using the same function.
Input doesn't even have to be a std::string
, it could be a std::vector
, a simple array or any type for which an overload of begin()
and end()
is provided (requirements of range-for loop).
Another advantage compared to simply returning an std::string
from the function is that you don't have to create a temporary string for the result which avoids memory allocations which should improve performance.
#include <iostream>
#include <string>
#include <iterator>
template< typename Range, typename OutputIterator >
OutputIterator copy_escaped( const Range& in, OutputIterator out ){
for( const auto& c : in ){
switch( c ){
case '"':
*out++ = '\\';
*out++ = '"';
break;
case '\\':
*out++ = '\\';
*out++ = '\\';
break;
case '\n':
*out++ = '\\';
*out++ = 'n';
break;
case '\r':
*out++ = '\\';
*out++ = 'r';
break;
case '\t':
*out++ = '\\';
*out++ = 't';
break;
// Could add more stuff to escape here
// case ...:
default:
*out++ = c;
}
}
return out;
}
You could easily extend the function to escape additional characters.
Usage examples:
int main()
{
std::string s = "abc\"def\\hhh\"i";
// output normal
std::cout << s << std::endl;
// output escaped
copy_escaped( s, std::ostream_iterator<char>( std::cout ) );
std::cout << std::endl;
// output escaped to other string
std::string escaped_s;
escaped_s.reserve( s.size() ); // not required but improves performance
copy_escaped( s, back_inserter( escaped_s ) );
std::cout << escaped_s << std::endl;
}
Upvotes: 2
Reputation: 1346
It is very simple to write such functionality:
std::string to_quoted(std::string const& src) {
std::string result;
result.reserve(src.size()); // Not necessary but makes the code more efficient (mentioned in comments)
for (std::size_t i = 0; i < src.length(); i++) {
switch (src[i]) {
case '"': result += "\\""; break;
case '\\': result += "\\\\"; break;
// ...
default: result += src[i];
}
}
return result;
}
There may be better solutions, I think this is the simplest and quickest one. I don't understand what you mean by "defining another string", maybe you mean constructing another string is disallowed, in that case just output to the stream instead of concatenating characters.
Upvotes: 4