代码之家  ›  专栏  ›  技术社区  ›  NullUserException Mark Roddy

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

  •  12
  • NullUserException Mark Roddy  · 技术社区  · 15 年前

    假设我有一根像这样的绳子:

    string hex = "48656c6c6f";
    

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

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

    那我怎么能得到 "hello" "48656c6c6f" 不需要创建一个查找ASCII表? atoi() 显然在这里行不通。

    5 回复  |  直到 15 年前
        1
  •  15
  •   James Curran    15 年前
    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
  •  18
  •   zwol    9 年前

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

    < PRE> <代码> //c++ 98保证“0”、“1”、…9'是连续的。 //它只保证“a”……F'和'A'…'F是 //按递增顺序,但只有两种可选编码 //仍由使用的基本源字符集 //今天的任何人(ASCII和EBCDIC)都会使它们连续。 无符号字符HexVal(无符号字符C) { if('0'<=c&&c<='9') 返回C′0; 否则,如果(“a”<=c&&c<='f') 返回C-‘A’+10; 否则,如果(“A”<=C&&C<='F') 返回C-‘A’+10; 否则中止(); } < /代码>

    所以整串看起来像这样:

    void hex2ascii(const string&in,string&out)
    {
    清除();
    out.reserve(in.length()/2);
    for(string::const_迭代器p=in.begin();p!=in.end();P++)
    {
    无符号字符c=十六进制(*p);
    P+;
    if(p==in.end())break;//最后一位不完整-应报告错误
    c=(c<<4)+hexval(*p);/+优先于<<
    向外。向后推(c);
    }
    }
    < /代码> 
    
    

    当存在strtol时,您可能会合理地问为什么会这样做,并且使用它的代码明显更少(如james curran的答案)。好吧,这种方法是一个完整的十进制数量级->em>慢一些,因为它复制每个两字节块(可能分配堆内存这样做),然后调用一个一般的文本到数字转换例程,该例程不能像上面的专门代码那样高效地写入。Christian的方法(使用IStringstream)比慢5倍。这是一个基准图——你甚至可以用一小块要解码的数据来分辨不同之处,而且随着差异的增大,它变得明显了。(注意两个轴都在对数刻度上。)

    这是过早的优化吗?不,这是一种在图书馆例行程序中被推挤的操作,被遗忘了,然后每秒调用数千次。它需要尖叫。几年前,我做了一个项目,在内部大量使用了sha1校验和——我们通过将它们存储为原始字节而不是十六进制(hex),在普通操作上获得了10-20%的加速,只有在我们必须向用户展示它们时才进行转换——这就是已经被调到死亡的转换函数。一个人可能更喜欢简洁到这里的性能,这取决于更大的任务是什么,但是如果是的话,为什么你在C++中编码?

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

    所以要做整个字符串看起来是这样的:

    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 而且使用它的代码要少得多(如詹姆斯·科伦的答案)。嗯,这种方法是

    Benchmark comparison plot

        3
  •  6
  •   András Czigány    10 年前

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

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

        4
  •  4
  •   Christian Ammer    15 年前
    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
  •  0
  •   schnaader    15 年前