Как преобразовать строку шестнадцатеричных значений в строку?
Скажем, у меня есть строка вроде:
string hex = "48656c6c6f";
Где каждые два символа соответствуют шестнадцатеричному представлению их ASCII, значение, например:
0x48 0x65 0x6c 0x6c 0x6f = "Hello"
Так как я могу получить "hello"
от "48656c6c6f"
без необходимости создания таблицы поиска ASCII? atoi()
очевидно, не будет работать здесь.
5 ответов
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);
}
Шестнадцатеричные цифры очень легко конвертировать в двоичные:
// 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) в пять раз медленнее. Вот эталонный график - вы можете различить разницу даже с небольшим блоком данных для декодирования, и он становится явным по мере увеличения различий. (Обратите внимание, что обе оси находятся в логарифмическом масштабе.)
Это преждевременная оптимизация? Конечно нет. Это та операция, которую запихивают в рутину библиотеки, о которой забывают, а затем вызывают тысячи раз в секунду. Это должно кричать. Несколько лет назад я работал над проектом, в котором очень интенсивно использовались контрольные суммы SHA1 - мы получили ускорение на 10-20% для обычных операций, сохраняя их в виде необработанных байтов вместо шестнадцатеричных, преобразовывая их только тогда, когда нам нужно было показать их пользователь - и это было с функциями преобразования, которые уже были настроены на смерть. Кто-то может честно предпочесть краткость производительности здесь, в зависимости от того, что является более крупной задачей, но если это так, с какой стати вы кодируете на C++?
Кроме того, с педагогической точки зрения, я думаю, что полезно показать примеры, написанные вручную, для решения этой проблемы; это показывает больше о том, что компьютер должен делать.
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;
Я не могу комментировать, но в решении zwol есть ошибка:
c = c << 4 + hexval(*p);
правильно
c = (c << 4) + hexval(*p);
так как оператор сдвига имеет меньший приоритет, чем добавить
strtol должен делать эту работу, если вы добавите 0x
к каждой паре шестнадцатеричных цифр.