14

重複の可能性:
バイト配列を16進文字列に、またはその逆にどのように変換しますか?

この変換を行うには、効率的で高速な方法が必要です。私は2つの異なる方法を試しましたが、それらは私にとって十分に効率的ではありません。巨大なデータを使用するアプリケーションでこれをリアルタイムで実行する他の迅速な方法はありますか?

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

3 に答える 3

28

本当に効率が必要な場合は、次のようにします。

  • 部分文字列を作成しないでください
  • イテレータを作成しないでください

または、効率ではなく単純化のために、再スローするブロック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);
}
于 2013-01-15T06:58:37.063 に答える
5

ジョンの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);
    }
}
于 2013-01-15T09:55:40.197 に答える
5

私は他の質問からベンチマークコードを取り、ここで与えられた16進数からバイトへのメソッドをテストするためにそれを作り直しました:

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)

HexToBytesJonJonの最初のバージョンであり、HexToBytesJon22番目のバリアントです。 は、 CodesInChaosの推奨コード HexToBytesJonCiCを含むJonのバージョンです。上記の両方に基づいていますが、エラーチェックと分岐を回避する代替のニブル変換を使用した私の試みです:HexToBytesJase

    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;
    }
于 2013-01-15T10:19:41.537 に答える