Can we convert a hex string to a byte array using a built-in function in C# or do I have to make a custom method for this?
4 Answers
Here's a nice fun LINQ example.
public static byte[] StringToByteArray(string hex) {
return Enumerable.Range(0, hex.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
.ToArray();
}
18 Comments
Kevin P. Rice
Good heavens!! Do you realize how INEFFICIENT that is??? Sure, it's fun, but LINQ is overused for things that should be done otherwise! LINQ code requires .NET 3.5 and requires referencing System.Core (which might otherwise not be needed). See the duplicate article for efficient solutions.
Karsten
It's probably meant to be fun, not efficient
Michael Richardson
Continually impressed with LINQ's elegance and versatility
dviljoen
Came up with this to go the other direction. In case anyone else needs it... public static string ByteArrayToBinHex( this byte[] bytes ) { return bytes.Select( b => b.ToString( "X2" ) ).Aggregate( ( s1, s2 ) => s1 + s2 ); }
Hossein Shahdoost
The shorter version would be,
Enumerable.Range(0, hex.Length / 2) .Select(x => Convert.ToByte(hex.Substring(x * 2, 2), 16)) .ToArray() |
I did some research and found out that byte.Parse() is even slower than Convert.ToByte().
The fastest conversion I could come up with uses approximately 15 ticks per byte.
public static byte[] StringToByteArrayFastest(string hex) {
if (hex.Length % 2 == 1)
throw new Exception("The binary key cannot have an odd number of digits");
byte[] arr = new byte[hex.Length >> 1];
for (int i = 0; i < hex.Length >> 1; ++i)
{
arr[i] = (byte)((GetHexVal(hex[i << 1]) << 4) + (GetHexVal(hex[(i << 1) + 1])));
}
return arr;
}
public static int GetHexVal(char hex) {
int val = (int)hex;
//For uppercase A-F letters:
//return val - (val < 58 ? 48 : 55);
//For lowercase a-f letters:
//return val - (val < 58 ? 48 : 87);
//Or the two combined, but a bit slower:
return val - (val < 58 ? 48 : (val < 97 ? 55 : 87));
}
// also works on .NET Micro Framework where (in SDK4.3) byte.Parse(string) only permits integer formats.
21 Comments
CainKellye
I tried that, but somehow this is slightly faster. Maybe because the difference between the Heap and the Stack.
John Nicholas
to answer that you would need to know a lot about how the compiler makes its decisions about automatic inlining
bytefire
The bytes are in same order as hex chars on my side. What do you mean by reverse?
StingyJack
I just found this code pasted into a program I have to maintain. It no longer compiles and throws a CS0307 (variable 'i' cannot be used with type args) and a CS0118 ('hex' is a variable but used as a type). Using the bitwise shifting (instead of a plain old "/ 2") may seem cool but this is a clear case of premature optimization evil for 99.99% of developers who comes to this question.
StingyJack
@RobertSnyder - my point isn't about the compilation (though it was more or less broken overnight with no recent changes to the build server). We had a consultant copy paste this code into a program that did not need this level of performance. .
|
The following code changes the hexadecimal string to a byte array by parsing the string byte-by-byte.
public static byte[] ConvertHexStringToByteArray(string hexString)
{
if (hexString.Length % 2 != 0)
{
throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, "The binary key cannot have an odd number of digits: {0}", hexString));
}
byte[] data = new byte[hexString.Length / 2];
for (int index = 0; index < data.Length; index++)
{
string byteValue = hexString.Substring(index * 2, 2);
data[index] = byte.Parse(byteValue, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
}
return data;
}
3 Comments
Noli
Should it not be "for (int index = 0; index < HexAsBytes.Length; index++)" ?
Moeez
68016101061B4A60193390662046804020422044204000420040402060226024676DB16 with this i am getting The binary key cannot have an odd number of digitsDominik Szymański
@Moeez And did you look at your input and the message you're getting?
I think this may work.
public static byte[] StrToByteArray(string str)
{
Dictionary<string, byte> hexindex = new Dictionary<string, byte>();
for (int i = 0; i <= 255; i++)
hexindex.Add(i.ToString("X2"), (byte)i);
List<byte> hexres = new List<byte>();
for (int i = 0; i < str.Length; i += 2)
hexres.Add(hexindex[str.Substring(i, 2)]);
return hexres.ToArray();
}
BigInteger.Parse(str, System.Globalization.NumberStyles.HexNumber).ToByteArray().Reverse().ToArray()