c# 中从十六进制到字节的最轻量级转换? [复制]

Posted

技术标签:

【中文标题】c# 中从十六进制到字节的最轻量级转换? [复制]【英文标题】:Most light weight conversion from hex to byte in c#? [duplicate] 【发布时间】:2012-12-29 05:48:57 【问题描述】:

可能重复:How do you convert Byte Array to Hexadecimal String, and vice versa?

我需要一种高效且快速的方法来进行这种转换。我尝试了两种不同的方法,但它们对我来说不够有效。对于具有大量数据的应用程序,还有其他快速方法可以实时完成此任务吗?

  public byte[] StringToByteArray(string hex)
    
        return Enumerable.Range(0, hex.Length / 2).Select(x => Byte.Parse(hex.Substring(2 * x, 2), NumberStyles.HexNumber)).ToArray(); 
    

我觉得上面那个更有效率。

 public static byte[] stringTobyte(string hexString)
    
        try
        
            int bytesCount = (hexString.Length) / 2;
            byte[] bytes = new byte[bytesCount];
            for (int x = 0; x < bytesCount; ++x)
            
                bytes[x] = Convert.ToByte(hexString.Substring(x * 2, 2), 16);
            
            return bytes;
        
        catch
        
            throw;
        

【问题讨论】:

另一个问题虽然表面上是关于双向转换,但最终集中在从字节到十六进制的转换上。这个问题是关于另一个方向的最佳转换,所以 FWIW,我认为它增加了一些东西。 这绝对不是重复的,因为它为所提供的特定问题提供了一组非常集中的答案 【参考方案1】:

如果你真的需要效率,那么:

不要创建子字符串 不要创建迭代器

或者,去掉 try 块,这些块只有一个 catch 块,它重新抛出......虽然是为了简单而不是效率。

这将是一个非常有效的版本:

public static byte[] ParseHex(string hexString)

    if ((hexString.Length & 1) != 0)
    
        throw new ArgumentException("Input must have even number of characters");
    
    int length = hexString.Length / 2;
    byte[] ret = new byte[length];
    for (int i = 0, j = 0; i < length; i++)
    
        int high = ParseNybble(hexString[j++]);
        int low = ParseNybble(hexString[j++]);
        ret[i] = (byte) ((high << 4) | low);
    

    return ret;


private static int ParseNybble(char c)

    // TODO: Benchmark using if statements instead
    switch (c)
    
        case '0': case '1': case '2': case '3': case '4':
        case '5': case '6': case '7': case '8': case '9':
            return c - '0';
        case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
            return c - ('a' - 10);
        case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
            return c - ('A' - 10);
        default:
            throw new ArgumentException("Invalid nybble: " + c);
    
    return c;

TODO 指的是这样的替代方案。我没有测量哪个更快。

private static int ParseNybble(char c)

    if (c >= '0' && c <= '9')
    
        return c - '0';
    
    c = (char) (c & ~0x20);
    if (c >= 'A' && c <= 'F')
    
        return c - ('A' - 10);
    
    throw new ArgumentException("Invalid nybble: " + c);

【讨论】:

@MitchWheat:我怀疑是这样 - 它为每个字节创建一个新的字符串对象。尽管 GC 非常高效,但这仍然是真正不需要的额外工作。 @MitchWheat:我会在这里添加一个链接... @MitchWheat:谢谢 - 添加了返回声明。 是的,它更快,我已经检查过了。 if 变体中,您可以使用c &amp; ~0x20 折叠大小写测试【参考方案2】:

我从other question 中获取了基准代码,并对其进行了重新设计以测试此处给出的十六进制到字节方法:

HexToBytesJon: 36979.7 average ticks (over 150 runs)
HexToBytesJon2: 35886.4 average ticks (over 150 runs)
HexToBytesJonCiC: 31230.2 average ticks (over 150 runs)
HexToBytesJase: 15359.1 average ticks (over 150 runs)

HexToBytesJon 是Jon 的第一个版本,HexToBytesJon2 是第二个变体。 HexToBytesJonCiC 是 Jon 的版本,带有 CodesInChaos 的建议代码。 HexToBytesJase 是我的尝试,基于上述两种方法,但采用替代 nybble 转换,避免错误检查和分支:

    public static byte[] HexToBytesJase(string hexString)
    
        if ((hexString.Length & 1) != 0)
        
            throw new ArgumentException("Input must have even number of characters");
        
        byte[] ret = new byte[hexString.Length/2];
        for (int i = 0; i < ret.Length; i++)
        
            int high = hexString[i*2];
            int low = hexString[i*2+1];
            high = (high & 0xf) + ((high & 0x40) >> 6) * 9;
            low = (low & 0xf) + ((low & 0x40) >> 6) * 9;

            ret[i] = (byte)((high << 4) | low);
        

        return ret;
    

【讨论】:

很奇怪,在我的测试中,我的代码比 Jon 的快,而 Jon 的两个解决方案的速度基本相同。您是否在没有附加调试器的情况下运行? 糟糕,我正在运行发布版,但使用了调试器。我会修改结果! 我也改了一点ParseHex,去掉j,改变了循环的终止条件。 是的,我已经获取了您更新的代码,看起来大致相同,但我会更新数字。 据我所知,这不会检测到无效数据。 OP可能需要也可能不需要,但我怀疑它与性能有关。 (这段代码中的分支要少得多。)【参考方案3】:

作为 Jon 的 if 的变体,基于 ParseNybble

public static byte[] ParseHex(string hexString)

    if ((hexString.Length & 1) != 0)
    
        throw new ArgumentException("Input must have even number of characters");
    
    byte[] ret = new byte[hexString.Length / 2];
    for (int i = 0; i < ret.Length; i++)
    
        int high = ParseNybble(hexString[i*2]);
        int low = ParseNybble(hexString[i*2+1]);
        ret[i] = (byte) ((high << 4) | low);
    

    return ret;


private static int ParseNybble(char c)

    unchecked
    
        uint i = (uint)(c - '0');
        if(i < 10)
            return (int)i;
        i = ((uint)c & ~0x20u) - 'A';
        if(i < 6)
            return (int)i+10;
        throw new ArgumentException("Invalid nybble: " + c);
    

【讨论】:

以上是关于c# 中从十六进制到字节的最轻量级转换? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

在Java中从整数转换为二进制时保留整个字节[重复]

在 C# 中从十进制转换时会失去精度吗?

解释类型转换如何在 C 中从 int 到 short 的位级别工作

C# 校验并转换 16 进制字符串到字节数组

十六进制字符串到字节数组 C# [重复]

十六进制字符串的字节转换在 C# 中使用字母字符“G”及更高版本一直失败