2014-07-24 11 views
5

ho una stringa di byte che è simile al seguente:suddivisione di un testo di byte da vettore di byte in C++

"1,3,8,b,e,ff,10" 

Come dovrei dividere questa stringa in uno std :: vector di byte che contengono i seguenti valori:

[0x01, 0x03, 0x08, 0x0b, 0x0E, 0xFF, 0x10]

sto cercando di dividere la stringa usando '' come delimitatore, ma sto avendo qualche difficoltà a trovare questo lavorare. Qualcuno può darmi una mano su come realizzare questo?

così ho provato questo:

std::istringstream iss("1 3 8 b e ff 10"); 
    BYTE num = 0; 
    while(iss >> num || !iss.eof()) 
    { 
     if(iss.fail()) 
     { 
      iss.clear(); 
      std::string dummy; 
      iss >> dummy; 
      continue; 
     } 
     dataValues.push_back(num); 
    } 

Ma questo spinge i valori ASCII di byte nel vettore:

49 //1 
51 //3 
56 //8 
98 //b 
101 //e 
102 //f 
102 //f 
49 //1 
48 //0 

Sto invece cercando di riempire il vettore con:

0x01 
0x03 
0x08 
0x0b 
0x0e 
0xff 
0x10 
+2

Probabilmente dovresti pubblicare la parte pertinente del tuo codice non funzionante in modo che le persone qui possano aiutarti a risolverlo. –

+3

Utilizzare ['std :: istringstream'] (http://en.cppreference.com/w/cpp/io/basic_istringstream) in combinazione con [' std :: hex'] (http: //en.cppreference. com/w/cpp/io/manip/hex) Manipolatore I/O. Saltare i caratteri ',' può essere fatto come [mostrato qui] (http://stackoverflow.com/a/24520662/1413395). –

+0

@PaulR Ho appena effettuato la modifica. – user3330644

risposta

1

You' ho appena mancava per adattare alcuni piccoli problemi che appaiono con il caso d'uso per il linked answer dal mio commento:

std::istringstream iss("1,3,8,b,e,ff,10"); 
    std::vector<BYTE> dataValues; 

    unsigned int num = 0; // read an unsigned int in 1st place 
          // BYTE is just a typedef for unsigned char 
    while(iss >> std::hex >> num || !iss.eof()) { 
     if(iss.fail()) { 
      iss.clear(); 
      char dummy; 
      iss >> dummy; // use char as dummy if no whitespaces 
          // may occur as delimiters 
      continue; 
     } 
     if(num <= 0xff) { 
      dataValues.push_back(static_cast<BYTE>(num)); 
     } 
     else { 
      // Error single byte value expected 
     } 
    } 

è possibile vedere l'esempio completamente funzionante here on ideone.

0

Un codice di esempio funzionante (testato in GCC 4.9.0 con C++ 11):

Il file save.txt contiene: 1,3,8,b,e,ff,10 come prima e unica linea.

uscita:

1 
3 
8 
b 
e 
ff 
10 

L'idea è:

  • Usa std :: getline per leggere riga per riga.
  • Utilizzare boost :: split per dividere la linea in base al separatore.
  • Utente std :: stringstream per convertire da stringa esadecimale a carattere non firmato.

Codice:

#include <fstream> 
#include <boost/algorithm/string/split.hpp> 
#include <boost/algorithm/string/classification.hpp> 
#include <boost/lexical_cast.hpp> 

int main(int argc, char* argv[]) { 
    std::ifstream ifs("e:\\save.txt"); 

    std::string line; 
    std::vector<std::string> tokens; 
    std::getline(ifs, line); 
    boost::split(tokens, line, boost::is_any_of(",")); 

    std::vector<unsigned char> values; 
    for (const auto& t : tokens) { 
     unsigned int x; 
     std::stringstream ss; 
     ss << std::hex << t; 
     ss >> x; 

     values.push_back(x); 
    } 

    for (auto v : values) { 
     std::cout << std::hex << (unsigned long)v << std::endl; 
    } 

    return 0; 
} 
0

Proprio per dimostrare un'altra, probabilmente molto più veloce, modo di fare le cose Potreste leggere tutto in un array e utilizzando un iteratore personalizzato per fare la conversione.

class ToHexIterator : public std::iterator<std::input_iterator_tag, int>{ 
    char* it_; 
    char* end_; 
    int current_; 
    bool isHex(const char c){ 
     return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); 
    } 
    char toUpperCase(const char c){ 
     if (c >= 'a' && c <= 'f'){ 
      return (c - 'a') + 'A'; 
     } 
     return c; 
    } 
    int toNibble(const char c){ 
     auto x = toUpperCase(c); 
     if (x >= '0' && x <= '9'){ 
      return x - '0'; 
     } 
     else { 
      return (x - 'A') + 10; 
     } 
    } 
public: 
    ToHexIterator() :it_{ nullptr }, end_{ nullptr }, current_{}{}     //default constructed means end iterator 
    ToHexIterator(char* begin, char* end) :it_{ begin }, end_{ end }, current_{}{ 
     while (!isHex(*it_) && it_ != end_){ ++it_; }; //make sure we are pointing to valid stuff 
     ++(*this); 
    } 
    bool operator==(const ToHexIterator &other){ 
     return it_ == nullptr && end_ == nullptr && other.it_ == nullptr && other.end_ == nullptr; 
    } 
    bool operator!=(const ToHexIterator &other){ 
     return !(*this == other); 
    } 
    int operator*(){ 
     return current_; 
    } 
    ToHexIterator & operator++(){ 
     current_ = 0; 
     if (it_ != end_) { 
      while (isHex(*it_) && it_ != end_){ 
       current_ <<= 4; 
       current_ += toNibble(*it_); 
       ++it_; 
      }; 
      while (!isHex(*it_) && it_ != end_){ ++it_; }; 
     } 
     else { 
      it_ = nullptr; 
      end_ = nullptr; 
     } 
     return *this; 
    } 
    ToHexIterator operator++(int){ 
     ToHexIterator temp(*this); 
     ++(*this); 
     return temp; 
    } 
}; 

Il caso d'uso di base sarebbe simile:

char in[] = "1,3,8,b,e,ff,10,--"; 
std::vector<int> v; 
std::copy(ToHexIterator{ std::begin(in), std::end(in) }, ToHexIterator{}, std::back_inserter(v)); 

Si noti che può essere più veloce di utilizzare una tabella guardare in alto per fare l'ascii esadecimale conversione bocconcino.

La velocità può essere MOLTO dipendente dall'ottimizzazione del compilatore e dalla piattaforma, tuttavia poiché alcune delle funzioni di istringstream sono implementate come virtual o puntatore alle funzioni (a seconda dell'implementazione della libreria standard) l'ottimizzatore ha problemi con esse. Nel mio codice non ci sono victuals o puntatori di funzioni e l'unico ciclo è all'interno dell'implementazione std :: copy con cui l'ottimizzatore è usato per gestire. È anche generalmente più veloce da eseguire in loop fino a quando due indirizzi sono uguali anziché in loop finché la cosa a cui punta il puntatore al cambiamento è uguale a qualcosa.Alla fine della giornata tutta la sua speculazione e il voodoo ma su MSVC13 sulla mia macchina la mia è di circa 10 volte più veloce. Ecco un esempio dal vivo http://ideone.com/nuwu15 su GCC che è da qualche parte tra 10x e 3x a seconda della corsa e dipende da quale test va prima (probabilmente a causa di alcuni effetti di cache).

Tutto sommato c'è indubbiamente più spazio per l'ottimizzazione ecc. E chiunque affermi che "il mio è sempre più veloce" a questo livello di astrazione si vende olio di serpente.

Update: utilizzando un tempo di compilazione generato guardano aumenta tavolo accelerare ulteriormente: http://ideone.com/ady8GY (notare che ho aumentato la dimensione della stringa di input per diminuire il rumore quindi questo non è direttamente paragonabile all'esempio precedente)

+0

Ciò che in realtà ti convince, che questo codice dovrebbe funzionare più velocemente rispetto allo standard stream 'operator >>' e l'implementazione di parsing esadecimale? –

+0

Ho aggiunto qualche spiegazione in più e un esempio dal vivo misurando i tempi della mia implementazione e un'approssimazione dell'implementazione (ho usato gli ints in entrambi i caratteri, piuttosto che in unsigned char ma non dovrebbe cambiare molto) – odinthenerd

Problemi correlati