Подтвердить что ты не робот

Как преобразовать строку шестнадцатеричных значений в строку?

Скажем, у меня есть строка вроде:

string hex = "48656c6c6f";

Где каждые два символа соответствуют шестнадцатеричному представлению их ASCII, например:

0x48 0x65 0x6c 0x6c 0x6f = "Hello"

Итак, как я могу получить "hello" из "48656c6c6f", не создавая таблицу ASCII поиска? atoi(), очевидно, не будет работать здесь.

4b9b3361

Ответ 1

int len = hex.length();
std::string newString;
for(int i=0; i< len; i+=2)
{
    string byte = hex.substr(i,2);
    char chr = (char) (int)strtol(byte.c_str(), null, 16);
    newString.push_back(chr);
}

Ответ 2

Шестнадцатеричные цифры очень легко конвертировать в двоичные:

// C++98 guarantees that '0', '1', ... '9' are consecutive.
// It only guarantees that 'a' ... 'f' and 'A' ... 'F' are
// in increasing order, but the only two alternative encodings
// of the basic source character set that are still used by
// anyone today (ASCII and EBCDIC) make them consecutive.
unsigned char hexval(unsigned char c)
{
    if ('0' <= c && c <= '9')
        return c - '0';
    else if ('a' <= c && c <= 'f')
        return c - 'a' + 10;
    else if ('A' <= c && c <= 'F')
        return c - 'A' + 10;
    else abort();
}

Итак, вся строка выглядит примерно так:

void hex2ascii(const string& in, string& out)
{
    out.clear();
    out.reserve(in.length() / 2);
    for (string::const_iterator p = in.begin(); p != in.end(); p++)
    {
       unsigned char c = hexval(*p);
       p++;
       if (p == in.end()) break; // incomplete last digit - should report error
       c = (c << 4) + hexval(*p); // + takes precedence over <<
       out.push_back(c);
    }
}

Вы могли бы разумно спросить, почему это можно сделать так, когда там strtol, и использование его значительно меньше кода (как в ответе Джеймса Каррана). Ну, этот подход является полным десятичным порядком медленнее, поскольку он копирует каждый двухбайтовый фрагмент (возможно, выделяя кучную память для этого), а затем вызывает общую процедуру преобразования текста в номер, которая не может быть написана так эффективно, как специализированный код выше. Христианский подход (с использованием istringstream) в пять раз медленнее этого. Здесь тестовый график - вы можете сказать разницу даже с крошечным блоком данных для декодирования, и это становится вопиющим, поскольку различия становятся больше. (Обратите внимание, что обе оси находятся в масштабе шкалы.)

Benchmark comparison plot

Является ли это преждевременной оптимизацией? Конечно нет. Это та операция, которая зацикливается в библиотечной рутине, забывается и затем называется тысячи раз в секунду. Ему нужно кричать. Несколько лет назад я работал над проектом, который очень сильно использовал контрольные суммы SHA1 - мы получили 10-20% ускорений на общих операциях, сохраняя их как необработанные байты вместо шестнадцатеричных, конвертируя только тогда, когда нам приходилось показывать их на пользователь - и это было с функциями преобразования, которые уже были настроены до смерти. Можно было бы честно отдать предпочтение производительности здесь, в зависимости от того, что представляет собой большая задача, но если да, то почему, на самом деле, вы кодируете на С++?

Кроме того, с педагогической точки зрения, я считаю полезным показать примеры с ручной кодировкой для такого рода проблем; он показывает больше о том, что должен делать компьютер.

Ответ 3

Я не могу комментировать, но решение zwol имеет ошибку:

c = c << 4 + hexval(*p);

правильно

c = (c << 4) + hexval(*p);

поскольку оператор сдвига имеет более низкий приоритет, чем add

Ответ 4

std::string str("48656c6c6f");
std::string res;
res.reserve(str.size() / 2);
for (int i = 0; i < str.size(); i += 2)
{
    std::istringstream iss(str.substr(i, 2));
    int temp;
    iss >> std::hex >> temp;
    res += static_cast<char>(temp);
}
std::cout << res;

Ответ 5

strtol должен выполнять задание, если вы добавляете 0x к каждой паре шестнадцатеричных цифр.