Pregunta

He copiado y pegado estos datos binarios fuera de SQL Server, que estoy No se puede consultar en este momento.

0xBAC893CAB8B7FE03C927417A2A3F6A60BD30FF35E250011CB25507EBFCD5223B

¿Cómo se convierte de nuevo a una matriz de bytes en c #?

¿Fue útil?

Solución

Algo como esto:

using System;

public static class Parser
{    
    static void Main()
    {
        string hex = "0xBAC893CAB8B7FE03C927417A2A3F6A6"
                     + "0BD30FF35E250011CB25507EBFCD5223B";
        byte[] parsed = ParseHex(hex);
        // Just for confirmation...
        Console.WriteLine(BitConverter.ToString(parsed));
    }

    public static byte[] ParseHex(string hex)
    {
        int offset = hex.StartsWith("0x") ? 2 : 0;
        if ((hex.Length % 2) != 0)
        {
            throw new ArgumentException("Invalid length: " + hex.Length);
        }
        byte[] ret = new byte[(hex.Length-offset)/2];

        for (int i=0; i < ret.Length; i++)
        {
            ret[i] = (byte) ((ParseNybble(hex[offset]) << 4) 
                             | ParseNybble(hex[offset+1]));
            offset += 2;
        }
        return ret;
    }        

    static int ParseNybble(char c)
    {
        if (c >= '0' && c <= '9')
        {
            return c-'0';
        }
        if (c >= 'A' && c <= 'F')
        {
            return c-'A'+10;
        }
        if (c >= 'a' && c <= 'f')
        {
            return c-'a'+10;
        }
        throw new ArgumentException("Invalid hex digit: " + c);
    }
}

(EDIT: Ahora ligeramente más eficiente - no hay subseries necesarios ...)

Es posible que ParseNybble podría ser más eficiente. Por ejemplo, un interruptor / caja puede será más eficiente:

    static int ParseNybble(char c)
    {
        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;
        }
        throw new ArgumentException("Invalid hex digit: " + c);
    }

o posiblemente una matriz de búsqueda:

    // Omitted for brevity... I'm sure you get the gist
    private static readonly int[] NybbleLookup = BuildLookup();

    private int ParseNybble(char c)
    {
        if (c > 'f')
        {
            throw new ArgumentException("Invalid hex digit: " + c);
        }
        int ret = NybbleLookup[c];
        if (ret == -1)
        {
            throw new ArgumentException("Invalid hex digit: " + c);
        }
        return ret;
    }

No he referenciado cualquiera de estos, y no tengo ni idea de lo que sería el más rápido. La solución actual es probablemente el más simple sin embargo.

Otros consejos

Considere el aprovechamiento de una clase de marco que ya expone la capacidad de realizar la conversión hex, XmlReader por ejemplo:

public static byte[] HexToBytes(this string hexEncodedBytes, int start, int end)
{
    int length = end - start;
    const string tagName = "hex";
    string fakeXmlDocument = String.Format("<{1}>{0}</{1}>",
                           hexEncodedBytes.Substring(start, length),
                           tagName);
    var stream = new MemoryStream(Encoding.ASCII.GetBytes(fakeXmlDocument));
    XmlReader reader = XmlReader.Create(stream, new XmlReaderSettings());
    int hexLength = length / 2;
    byte[] result = new byte[hexLength];
    reader.ReadStartElement(tagName);
    reader.ReadContentAsBinHex(result, 0, hexLength);
    return result;
}

uso:

string input = "0xBAC893CAB8B7FE03C927417A2A3F6A60BD30FF35E250011CB255";
byte[] bytes = input.HexToBytes(2, input.Length);

simple:

string hexnum = "0000000F"; // Represents 15
int value = int.Parse(hexnum, System.Globalization.NumberStyles.HexNumber);

Todo lo que tiene que recordar que hacer es para un int para dividir el número hexadecimal en grupos de 8 dígitos hexadecimales (hex son 4 bits cada uno, y el tipo CLR int es de 32 bits, por lo tanto 8 dígitos por int). También hay un byte.Parse () que funciona de la misma, pero desaparecen de dos dígitos hexadecimales a la vez.

Algo como esto:

    public byte[] ParseHexString(string text)
    {
        if ((text.Length % 2) != 0)
        {
            throw new ArgumentException("Invalid length: " + text.Length);
        }

        if (text.StartsWith("0x", StringComparison.InvariantCultureIgnoreCase))
        {
            text = text.Substring(2);
        }

        int arrayLength = text.Length / 2;
        byte[] byteArray = new byte[arrayLength];
        for (int i = 0; i < arrayLength; i++)
        {
            byteArray[i] = byte.Parse(text.Substring(i*2, 2), NumberStyles.HexNumber);
        }

        return byteArray;
    }

Usted tendrá que modificar esta un poco (por ejemplo, saltar sobre los dos primeros caracteres), pero sí manejar espacios en la cadena:

    /// <summary>
    /// Decodes a hex string, ignoring all non-hex characters, and stores
    /// the decodes series of bytes into the shared buffer. This returns
    /// the number of bytes that were decoded.
    /// <para>Hex characters are [0-9, a-f, A-F].</para>
    /// </summary>
    /// <param name="hexString">String to parse into bytes.</param>
    /// <param name="buffer">Buffer into which to store the decoded binary data.</param>
    /// <returns>The number of bytes decoded.</returns>
    private static int DecodeHexIntoBuffer(string hexString, byte[] buffer)
    {
        int count = 0;

        bool haveFirst = false;
        bool haveSecond = false;
        char first = '0';
        char second = '0';

        for (int i = 0; i < hexString.Length; i++)
        {
            if (!haveFirst)
            {
                first = hexString[i];
                haveFirst = char.IsLetterOrDigit(first);

                // we have to continue to the next iteration
                // or we will miss characters
                continue;
            }

            if (!haveSecond)
            {
                second = hexString[i];
                haveSecond = char.IsLetterOrDigit(second);
            }

            if (haveFirst && haveSecond)
            {
                string hex = "" + first + second;

                byte nextByte;
                if (byte.TryParse(hex, NumberStyles.HexNumber, null, out nextByte))
                {
                    // store the decoded byte into the next slot of the buffer
                    buffer[count++] = nextByte;
                }

                // reset the flags
                haveFirst = haveSecond = false;
            }
        }

        return count;
    }

manera lenta pero divertido: D

public static byte[] StringToByteArray(string hex)
{
    hex = hex.Replace(" ", "");
    hex = hex.Replace(":", "");
    return Enumerable.Range(0, hex.Length)
            .Where(x => x % 2 == 0)
            .Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
            .ToArray();
}

-jD

En realidad, hay una manera más fácil de convertir dos caracteres a la vez a un byte:

    /// <summary>
    /// This will convert a hex-encoded string to byte data
    /// </summary>
    /// <param name="hexData">The hex-encoded string to convert</param>
    /// <returns>The bytes that make up the hex string</returns>
    public static byte[] FromHex(string hexData)
    {
        List<byte> data = new List<byte>();
        string byteSet = string.Empty;
        int stringLen = hexData.Length;
        int length = 0;
        for (int i = 0; i < stringLen; i = i + 2)
        {
            length = (stringLen - i) > 1 ? 2 : 1;
            byteSet = hexData.Substring(i, length);

            // try and parse the data
            data.Add(Convert.ToByte(byteSet, 16 /*base*/));
        } // next set

        return data.ToArray();
    }

Yo lo uso para C #, desde un código similar en Java.

    private static char[] hexdigit = "0123456789abcdef".ToCharArray();

    public static string hexlify(string argbuf) {
        int arglen = argbuf.Length;
        char[] argca = argbuf.ToCharArray ();
        StringBuilder retbuf = new StringBuilder(arglen * 2);
        for (int i = 0; i < arglen; i++) {
            char ch = argca[i];
            retbuf.Append(hexdigit[(ch >> 4) & 0xF]);
            retbuf.Append(hexdigit[ch & 0xF]);
        }
        return retbuf.ToString();
    }

    public static string unhexlify(string argbuf) {
        int arglen = argbuf.Length;
        if (arglen % 2 != 0) {
            throw new ArgumentOutOfRangeException ("Odd-length string");
        }
        char[] argca = argbuf.ToCharArray ();
        StringBuilder retbuf = new StringBuilder(arglen / 2);
        for (int i = 0; i < arglen; i += 2) {
            int top = Convert.ToInt32 (argca[i].ToString (), 16);
            int bot = Convert.ToInt32 (argca[i + 1].ToString (), 16);
            if (top == -1 || bot == -1) {
                throw new ArgumentOutOfRangeException ("Non-hexadecimal digit found");
            }
            retbuf.Append((char) ((top << 4) + bot));
        }
        return retbuf.ToString();
    }
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top