credo che qualsiasi risposta canonica (wRTle note di taglie) comporterebbe alcune fasi distinte nella soluzione:
- errore durante il controllo per l'ingresso valido
- controllo Lunghezza e
- contenuto dei dati di controllo di conversione
- Elemento creazione
- uscita
Dato th E l'utilità di tali conversioni, la soluzione dovrebbe probabilmente includere una certa flessibilità w.r.t. i tipi utilizzati e le impostazioni locali richieste.
Fin dall'inizio, data la data della richiesta di una "risposta più canonica" (circa agosto 2014), verrà applicato un uso liberale di C++ 11.
Una versione annotata del codice, con i tipi corrispondenti alla OP:
std::vector<std::uint8_t> convert(std::string const& src)
{
// error check on the length
if ((src.length() % 2) != 0) {
throw std::invalid_argument("conversion error: input is not even length");
}
auto ishex = [] (decltype(*src.begin()) c) {
return std::isxdigit(c, std::locale()); };
// error check on the data contents
if (!std::all_of(std::begin(src), std::end(src), ishex)) {
throw std::invalid_argument("conversion error: input values are not not all xdigits");
}
// allocate the result, initialised to 0 and size it to the correct length
std::vector<std::uint8_t> result(src.length()/2, 0);
// run the actual conversion
auto str = src.begin(); // track the location in the string
std::for_each(result.begin(), result.end(), [&str](decltype(*result.begin())& element) {
element = static_cast<std::uint8_t>(std::stoul(std::string(str, str + 2), nullptr, 16));
std::advance(str, 2); // next two elements
});
return result;
}
La versione del modello del codice aggiunge flessibilità;
template <typename Int /*= std::uint8_t*/,
typename Char = char,
typename Traits = std::char_traits<Char>,
typename Allocate = std::allocator<Char>,
typename Locale = std::locale>
std::vector<Int> basic_convert(std::basic_string<Char, Traits, Allocate> const& src, Locale locale = Locale())
{
using string_type = std::basic_string<Char, Traits, Allocate>;
auto ishex = [&locale] (decltype(*src.begin()) c) {
return std::isxdigit(c, locale); };
if ((src.length() % 2) != 0) {
throw std::invalid_argument("conversion error: input is not even length");
}
if (!std::all_of(std::begin(src), std::end(src), ishex)) {
throw std::invalid_argument("conversion error: input values are not not all xdigits");
}
std::vector<Int> result(src.length()/2, 0);
auto str = std::begin(src);
std::for_each(std::begin(result), std::end(result), [&str](decltype(*std::begin(result))& element) {
element = static_cast<Int>(std::stoul(string_type(str, str + 2), nullptr, 16));
std::advance(str, 2);
});
return result;
}
La funzione convert()
può quindi essere basata sulla basic_convert()
come segue:
std::vector<std::uint8_t> convert(std::string const& src)
{
return basic_convert<std::uint8_t>(src, std::locale());
}
Live sample.
Ehi @Nirav, sembra che alcune risposte di seguito hanno contribuito a risolvere il problema. Se è così, sarebbe bello "accettare" la risposta che ti piace di più (con la casella di controllo a sinistra della risposta). Puoi (o sarai in grado di avere abbastanza reputazione) [votare su] (http://stackoverflow.com/privileges/vote-up) tutte le risposte utili. –