如何将十六进制值字符串转换为字符串?

发布于 2024-09-25 00:11:18 字数 284 浏览 1 评论 0原文

假设我有一个如下字符串:

string hex = "48656c6c6f";

其中每两个字符对应于其 ASCII 值的十六进制表示形式,例如:

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

那么如何从 "48656c6c6f" 获取 "hello"无需创建查找 ASCII 表? atoi() 显然在这里不起作用。

Say I have a string like:

string hex = "48656c6c6f";

Where every two characters correspond to the hex representation of their ASCII, value, eg:

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

So how can I get "hello" from "48656c6c6f" without having to create a lookup ASCII table? atoi() obviously won't work here.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

梅倚清风 2024-10-02 00:11:18
int len = hex.length();
std::string newString;
for(int i=0; i< len; i+=2)
{
    std::string byte = hex.substr(i,2);
    char chr = (char) (int)strtol(byte.c_str(), null, 16);
    newString.push_back(chr);
}
int len = hex.length();
std::string newString;
for(int i=0; i< len; i+=2)
{
    std::string byte = hex.substr(i,2);
    char chr = (char) (int)strtol(byte.c_str(), null, 16);
    newString.push_back(chr);
}
离旧人 2024-10-02 00:11:18

十六进制数字很容易转换为二进制:

// 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 的情况下会这样做,并且使用它的代码明显更少(如詹姆斯·柯兰的回答)。嗯,这种方法慢了一个完整的十进制数量级,因为它复制每个两字节块(可能为此分配堆内存),然后调用通用的文本到数字转换例程无法像上面的专用代码那样高效地编写。 Christian 的方法(使用 istringstream)比那个方法慢五倍。这是一个基准图 - 即使需要解码一小块数据,您也可以分辨出差异,并且随着差异变大,差异会变得明显。 (请注意,两个轴均采用对数刻度。)

基准比较图

这是过早优化吗?天哪,不。这种操作会被塞进库例程中,被遗忘,然后每秒调用数千次。它需要尖叫。几年前,我参与了一个项目,该项目在内部大量使用了 SHA1 校验和——通过将它们存储为原始字节而不是十六进制,仅当我们必须将它们显示给我们时才进行转换,我们在常见操作上获得了 10-20% 的加速。用户——那是已经被调到死的转换函数。老实说,人们可能更喜欢简洁而不是性能,这取决于更大的任务是什么,但如果是这样,你到底为什么用 C++ 编码?

另外,从教学的角度来看,我认为展示此类问题的手工编码示例是有用的;它揭示了更多关于计算机必须做什么的信息。

Hex digits are very easy to convert to binary:

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

So to do the whole string looks something like this:

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

You might reasonably ask why one would do it this way when there's strtol, and using it is significantly less code (as in James Curran's answer). Well, that approach is a full decimal order of magnitude slower, because it copies each two-byte chunk (possibly allocating heap memory to do so) and then invokes a general text-to-number conversion routine that cannot be written as efficiently as the specialized code above. Christian's approach (using istringstream) is five times slower than that. Here's a benchmark plot - you can tell the difference even with a tiny block of data to decode, and it becomes blatant as the differences get larger. (Note that both axes are on a log scale.)

Benchmark comparison plot

Is this premature optimization? Hell no. This is the kind of operation that gets shoved in a library routine, forgotten about, and then called thousands of times a second. It needs to scream. I worked on a project a few years back that made very heavy use of SHA1 checksums internally -- we got 10-20% speedups on common operations by storing them as raw bytes instead of hex, converting only when we had to show them to the user -- and that was with conversion functions that had already been tuned to death. One might honestly prefer brevity to performance here, depending on what the larger task is, but if so, why on earth are you coding in C++?

Also, from a pedagogical perspective, I think it's useful to show hand-coded examples for this kind of problem; it reveals more about what the computer has to do.

夜雨飘雪 2024-10-02 00:11:18
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;
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;
感受沵的脚步 2024-10-02 00:11:18

如果您添加 0xstrtol 应该可以完成这项工作到每个十六进制数字对。

strtol should do the job if you add 0x to each hex digit pair.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文