Storing hexadecimal values from a std::string in a

2019-04-01 00:21发布

问题:

Let's say you've got a std::string("DEADBEEF"), what would be the most elegant way to store each two values in a std::vector (most likely a std::vector<unsigned char>, if possible) so the std::vector would look a little like { 0xDE, 0xAD, 0xBE, 0xEF } (if it was an array)? And what would be the nicest way to undo that (std::vector<unsigned char> -> std::string).

回答1:

how about (no fancy stl juggling though):

#include <string>
#include <vector>

// exception thrown by the encoder
class DecodeError {
public:
    DecodeError() {}
    DecodeError(const char* s): msg(s) {}
    DecodeError(const std::string& s): msg(s) {}
    const char* what() { return msg.c_str(); }
private:
    std::string msg;
};

class HexEncoder {
public:
    void decode(const std::string& str, std::vector<unsigned char>& v);
private:
    unsigned char decode(char);
};

void HexEncoder::decode(const std::string& s, std::vector<unsigned char>& v)
{
    if (s.size() % 2 != 0)
        throw DecodeError("invalid string length");

    v.reserve(s.size() / 2);
    std::string::const_iterator it=s.begin();
    while (it != s.end()) {
        unsigned char nibble1 = decode(*it++);
        unsigned char nibble2 = decode(*it++);
        v.push_back(nibble1 << 4 + nibble2);
    }
}

unsigned char HexEncoder::decode(char c)
{
    if (c >= '0' && c <= '9')
        return c - '0';
    if (c >= 'A' && c <= 'F')
        return c - 'A' + 10;
    if (c >= 'a' && c <= 'f')
        return c - 'a' + 10;
    throw DecodeError("invalid character");
}

int main()
{
    std::string s("DEADBEEF");

    std::vector<unsigned char> v;

    HexEncoder enc;
    enc.decode(s, v);
}


回答2:

for(std::iterator<string> it = str.begin(); it != str.end(); std::advance(it, 2))
{
    char tmp;
    std::copy(it, it + 2, tmp);
    scanf("%02X", &tmp);
    vect.push_back(tmp);
}

This is a rough draft of your conversion, but I'm not sure that it works correctly.



回答3:

I'd go for simple plain loops

int hexValue(int c)
{
    if (c >= '0' && c <= '9') return c - '0';
    if (c >= 'A' && c <= 'F') return c - 'A' + 10;
    if (c >= 'a' && c <= 'f') return c - 'a' + 10;
    return -1;
}

std::vector<unsigned char> toBin(const std::string& s)
{
    std::vector<unsigned char> result;
    for (int i=0,n=s.size(); i<n-1; i+=2)
    {
        int x1 = hexValue(s[i]);
        int x2 = hexValue(s[i+1]);
        if (x1 >= 0 && x2 >= 0)
            result.push_back(x1*16 + x2);
    }
    return result;
}

std::string toHex(const std::vector<unsigned char>buf)
{
    const char *hex = "0123456789ABCDEF";
    int n = buf.size();
    std::string result(n*2, ' ');
    for (int i=0; i<n; i++)
    {
        result[i*2] = hex[buf[i]>>4];
        result[i*2+1] = hex[buf[i]&15];
    }
    return result;
}

If you need this conversion to be very fast (assuming the input is big enough and formally correct) ...

std::vector<unsigned char> toBin(const std::string& s)
{
    static unsigned char H[256], L[256];
    if (L['1'] == 0)
    {
        for (int i=0; i<10; i++)
        {
            H['0'+i] = (i<<4);
            L['0'+i] = i;
        }
        for (int i=0; i<6; i++)
        {
            H['a'+i] = H['A'+i] = ((10+i)<<4);
            L['a'+i] = L['A'+i] = (10+i);
        }
    }
    std::vector<unsigned char> result(s.size()>>1);
    for (int i=0,n=s.size(); i<n-1; i+=2)
      result[i>>1] = H[s[i]]+L[s[i+1]];
    return result;
}


回答4:

As my project already depends on boost, I'd use boost/algorithm/hex.hpp:

#include <string>
#include <vector>
#include <iterator>

#include <boost/algorithm/hex.hpp>

...

string stringValue("DEADBEEF");
vector<unsigned char> vectorValue;

String to hex conversion:

boost::algorithm::unhex(stringValue, back_inserter(vectorValue));

For hex to string conversion:

boost::algorithm::hex(vectorValue, back_inserter(stringValue));