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;
}
Live demo.