2014-07-24 2 views
5

ich eine Reihe von Bytes haben, die wie folgt aussieht:Splitting eine Kette von Bytes zu Vektor von BYTES in C++

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

Wie würde ich diese Zeichenfolge in ein std geteilt :: vector von Bytes mit folgenden Werte:

[0x01, 0x03, 0x08, 0x0b, 0x0e, 0xff, 0x10]

ich versuche, mit dem String '' als Trennzeichen zu teilen, aber ich einige Probleme mit dieser bekommen arbeiten. Kann mir jemand helfen, wie das geht?

Ich habe dies so versucht:

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); 
    } 

Aber dies drückt die ascii-Byte-Werte in den Vektor:

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

ich stattdessen versuche ich, den Vektor mit zu füllen:

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

Sie sollten wahrscheinlich den relevanten Teil Ihres nicht funktionierenden Codes posten, damit die Leute hier Ihnen bei der Behebung helfen können. –

+3

Verwenden Sie ['std :: istringstream '] (http://en.cppreference.com/w/cpp/io/basic_istringstream) in Verbindung mit dem [' std :: hex'] (http: //en.cppreference. com/w/cpp/io/manip/hex) E/A-Manipulator. Das Überspringen der Zeichen ',' kann als [hier gezeigt] (http://stackoverflow.com/a/24520662/1413395) erfolgen. –

+0

@PaulR Ich habe gerade den Schnitt gemacht. – user3330644

Antwort

1

Sie‘ für die linked answer von meinem Kommentar hat gerade ein paar kleine Probleme vermissen mit Ihrem Anwendungsfall erscheinen, anzupassen:

können
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 
     } 
    } 

Sie das voll funktionstüchtiges Beispiel sehen here on ideone.

0

Ein funktionierender Beispielcode (Getestet in GCC 4.9.0 mit C++ 11):

Die Datei save.txt enthält: 1,3,8,b,e,ff,10 als erste und eindeutige Zeile.

Ausgang:

1 
3 
8 
b 
e 
ff 
10 

Die Idee ist:

  • Verwenden std :: getline Zeile für Zeile zu lesen.
  • Verwenden Sie boost :: split, um die Linie nach dem Separator zu teilen.
  • Benutzer std :: stringstream von hexadezimalen in vorzeichenlose Zeichen zu konvertieren.

Code:

#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

Just another zu demonstrieren, wahrscheinlich viel schneller, Art und Weise, Dinge zu tun alles, was in ein Array betrachten zu lesen und mit einem benutzerdefinierten Iterator der Umwandlung zu tun.

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; 
    } 
}; 

Der grundlegende Anwendungsfall würde wie folgt aussehen:

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)); 

Beachten Sie, dass es schneller sein kann, eine Nachschlagetabelle zu verwenden, um die ascii zu tun knabbern Umwandlung verhexen.

Geschwindigkeit kann sehr abhängig von Compiler-Optimierung und Plattform sein, aber da einige der istringstream-Funktionen als virtuals oder Zeiger auf Funktionen (abhängig von der Standard-Bibliothek-Implementierung) implementiert sind, hat der Optimierer Probleme mit ihnen. In meinem Code gibt es keine victuals oder Funktionszeiger, und die einzige Schleife ist in der std :: copy-Implementierung, mit der der Optimierer vertraut ist. Es ist auch im Allgemeinen schneller zu loopen, bis zwei Adressen gleich sind, anstatt zu loopen, bis die Sache, auf die ein Zeiger hinweist, gleich ist.Am Ende des Tages ist alles Spekulationen und Voodoo aber auf MSVC13 auf meiner Maschine etwa 10x schneller. Hier ist ein Live-Beispiel http://ideone.com/nuwu15 auf GCC, das irgendwo zwischen 10x und 3x liegt, abhängig vom Lauf und abhängig davon, welcher Test zuerst geht (wahrscheinlich wegen einiger Caching-Effekte).

Alles in allem gibt es zweifellos mehr Platz für Optimierung etc. und jeder, der auf dieser Abstraktionsebene sagt "meins ist immer schneller", verkauft Schlangenöl.

Update: eine Kompilierung mit generierten Tabelle erhöht die Geschwindigkeit weiter sehen: http://ideone.com/ady8GY (beachten Sie, dass ich die Größe der Eingabezeichenfolge erhöhtes Rauschen zu verringern, so dass diese auf das obige Beispiel nicht direkt vergleichbar ist)

+0

Was überzeugt Sie eigentlich, dass dieser Code schneller als der Standardstream 'operator >>' und die hexadezimale Implementierung funktionieren sollte? –

+0

Ich habe weitere Erklärungen und ein Live-Beispiel hinzugefügt, um das Timing meiner Implementierung und eine Approximation Ihrer Implementierung zu messen (Ich habe Ints in beiden anstelle von unsigned char verwendet, aber es sollte sich nicht viel ändern) – odinthenerd