Convert the <char> vector to a conversion string
I would like to convert vector<char>
to std::string
and do the conversion this way.
I am almost there, but the result of the code below is vector<string>
, while I would like to have one line (concatenation of all parts of the line in the vector).
See my sample code for more details.
string ConvertHexToAscii(const char input) { std::ostringstream oss; oss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(input); return oss.str(); } vector<char> readBuffer; // this is my input readBuffer.push_back(0x1c); readBuffer.push_back(0x09); vector<string> resultVec; std::transform(readBuffer.begin(), readBuffer.end() , back_inserter(resultVec) , ConvertHexToAscii); // resultVec[0] = "1C"; // resultVec[1] = "09";
As a result, I need a line containing "1C09". How to achieve this with std::transform
?
You were almost there; it works:
std::stringstream sstr; std::transform( input.begin(), input.end(), std::ostream_iterator<std::string>(sstr, ""), ConvertHexToAscii);
But, unfortunately, this creates a lot of string streams, which is inefficient. Ideally, ConvertHexToAscii
(incorrectly named, C ++ does not know about encodings), the function would directly use the underlying stream.
#include <iostream> #include <vector> #include <iomanip> #include <sstream> #include <numeric> std::string ConvertHexToAscii(std::string acc, char input) { std::ostringstream oss; oss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(input); return acc + oss.str(); } int main() { std::vector<char> readBuffer; // this is my input readBuffer.push_back(0x1c); readBuffer.push_back(0x09); std::cout << std::accumulate(readBuffer.begin(), readBuffer.end() , std::string(), ConvertHexToAscii) << std::endl; return 0; }
create your own back_insert_iterator (look at the code in stl lib, it’s pretty simple) for string types whose operator = operator is defined as
template< class string_type, class value_type > class back_insert_iterator { public: back_insert_iterator< _string_type >& operator = ( const value_type& val ) { container->append( val ) return *this; } };
You can do this using the function output iterator:
#include <iostream> #include <sstream> #include <string> #include <algorithm> #include <iterator> #include <iomanip> #include <boost/function_output_iterator.hpp> std::string ConvertHexToAscii(const char input) { std::ostringstream oss; oss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(input); return oss.str(); } int main() { std::vector<char> readBuffer; // this is my input readBuffer.push_back(0x1c); readBuffer.push_back(0x09); std::string temp; std::transform(readBuffer.begin(), readBuffer.end() , boost::make_function_output_iterator([&temp](const std::string& r) {temp.append(r);}) , ConvertHexToAscii); std::cout << temp << std::endl; }
I used lambda to call the append()
function in the result line, but if you don't have one, just use boost::bind
or just write an old-fashioned functor to do it for you.
With boost::bind
function output iterator is created as:
boost::make_function_output_iterator(boost::bind(static_cast<std::string& (std::string::*)(const std::string&)>(&std::string::append), &temp, _1))
instead of this. This is a bit awkward because you need to choose the right overload for std::string::append
.
While the real idea of using accumulation is not so bad, it can be more efficient for working with the stream directly, and not for creating so many temporary lines (although the semantics of moving can help with this):
std::ostringstream os; std::string temp = std::accumulate( readBuffer.begin(), readBuffer.end(), std::ref(os), [](std::ostream &os, const char input) -> std::reference_wrapper<std::ostream> { return os << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(input); }).str();
EDIT: But maybe it could be a little rethinking here, a simple profile would do too (even if it weren’t as semantically clean as accumulation):
std::ostringstream os; std::for_each(readBuffer.begin(), readBuffer.end(), [&os](const char input) mutable { os << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(input); }); std::string temp = os.str();
But everything can be better than creating a whole series of timelines.