Last active
May 30, 2019 12:57
-
-
Save sandrock/f38cf1b56a16e4d684398ac2117069ce to your computer and use it in GitHub Desktop.
C# convert a hexadecimal string to a byte array (tolerant to extra characters)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Home | |
{ | |
using System; | |
using System.Collections.Generic; | |
public static class ConvertEx | |
{ | |
/// <summary>Reads a hex string into bytes</summary> | |
public static IEnumerable<byte> HexadecimalStringToBytes(string hex) | |
{ | |
if (hex == null) | |
{ | |
throw new ArgumentNullException(nameof(hex)); | |
} | |
char c, c1 = default(char); | |
bool hasc1 = false; | |
unchecked | |
{ | |
for (int i = 0; i < hex.Length; i++) | |
{ | |
c = hex[i]; | |
bool isValid = 'A' <= c && c <= 'f' || 'a' <= c && c <= 'f' || '0' <= c && c <= '9'; | |
if (!hasc1) | |
{ | |
if (isValid) | |
{ | |
hasc1 = true; | |
} | |
} | |
else | |
{ | |
hasc1 = false; | |
if (isValid) | |
{ | |
yield return (byte)((GetHexVal(c1) << 4) + GetHexVal(c)); | |
} | |
else | |
{ | |
} | |
} | |
c1 = c; | |
} | |
} | |
} | |
/// <summary>Reads a hex string into a byte array</summary> | |
public static byte[] HexadecimalStringToByteArray(string hex) | |
{ | |
if (hex == null) | |
{ | |
throw new ArgumentNullException(nameof(hex)); | |
} | |
var bytes = new List<byte>(hex.Length / 2); | |
foreach (var item in HexadecimalStringToBytes(hex)) | |
{ | |
bytes.Add(item); | |
} | |
return bytes.ToArray(); | |
} | |
private static byte GetHexVal(char val) | |
{ | |
return (byte)(val - (val < 0x3A ? 0x30 : val < 0x5B ? 0x37 : 0x57)); | |
// ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^ ^^^^ | |
// digits 0-9 upper char A-Z a-z | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Home | |
{ | |
using Microsoft.VisualStudio.TestTools.UnitTesting; | |
using Should; | |
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
[TestClass] | |
public class ConvertExTests | |
{ | |
[TestMethod, ExpectedException(typeof(ArgumentNullException))] | |
public void HexadecimalStringToBytes_Null() | |
{ | |
var input = default(string); | |
var result = ConvertEx.HexadecimalStringToBytes(input).ToArray(); | |
} | |
[TestMethod] | |
public void HexadecimalStringToBytes_Empty() | |
{ | |
var input = string.Empty; | |
var result = ConvertEx.HexadecimalStringToBytes(input).ToArray(); | |
result.ShouldNotBeNull(); | |
result.Length.ShouldEqual(0); | |
} | |
[TestMethod] | |
public void HexadecimalStringToBytes_Simple() | |
{ | |
var input = "00a0FF00"; | |
var result = ConvertEx.HexadecimalStringToBytes(input).ToArray(); | |
result.ShouldNotBeNull(); | |
result.Length.ShouldEqual(4); | |
result.SequenceEqual(new byte[] { 0x00, 0xa0, 0xff, 0x00, }); | |
} | |
[TestMethod] | |
public void HexadecimalStringToBytes_AllChars() | |
{ | |
// generate 00-99 aa-ff AA-FF | |
var allStrings = new List<string>(); | |
var allBytes = new List<byte>(); | |
char c1, c2; | |
for (int i = 0; i < 16; i++) | |
{ | |
c1 = i < 10 ? ((char)('0' + i)) : ((char)('a' + i - 10)).ToString()[0]; | |
for (int j = 0; j < 16; j++) | |
{ | |
c2 = j < 10 ? ((char)('0' + j)) : ((char)('a' + j - 10)); | |
string value = c1.ToString() + c2; | |
allStrings.Add(value); | |
allStrings.Add(value.ToUpperInvariant()); | |
allBytes.Add((byte)(i * 16 + j)); | |
allBytes.Add((byte)(i * 16 + j)); | |
} | |
} | |
var input = string.Concat(allStrings); | |
var result = ConvertEx.HexadecimalStringToBytes(input).ToArray(); | |
result.ShouldNotBeNull(); | |
for (int i = 0; i < result.Length; i++) | |
{ | |
result[i].ShouldEqual(allBytes[i], $"At {i}, val \"{allStrings[i]}\" should eq {allBytes[i]}, not {result[i]}"); | |
} | |
result.Length.ShouldEqual(allBytes.Count); | |
} | |
[TestMethod] | |
public void HexadecimalStringToBytes_Skips() | |
{ | |
var input = " 00 a0 FF 00\r\n00-a0-FF-00 "; | |
var result = ConvertEx.HexadecimalStringToBytes(input).ToArray(); | |
result.ShouldNotBeNull(); | |
result.Length.ShouldEqual(8); | |
result.SequenceEqual(new byte[] { 0x00, 0xa0, 0xff, 0x00, 0x00, 0xa0, 0xff, 0x00, }); | |
} | |
[TestMethod] | |
public void HexadecimalStringToBytes_TooMuchTolerance() | |
{ | |
var input = "Hello worlds."; | |
// would you expect an exception here? now there is none. | |
var result = ConvertEx.HexadecimalStringToBytes(input).ToArray(); | |
result.ShouldNotBeNull(); | |
result.Length.ShouldEqual(1); | |
result.SequenceEqual(new byte[] { 0x1e, }); | |
} | |
[TestMethod, ExpectedException(typeof(ArgumentNullException))] | |
public void HexadecimalStringToByteArray_Null() | |
{ | |
var input = default(string); | |
var result = ConvertEx.HexadecimalStringToByteArray(input); | |
} | |
[TestMethod] | |
public void HexadecimalStringToByteArray_Empty() | |
{ | |
var input = string.Empty; | |
var result = ConvertEx.HexadecimalStringToByteArray(input); | |
result.ShouldNotBeNull(); | |
result.Length.ShouldEqual(0); | |
} | |
[TestMethod] | |
public void HexadecimalStringToByteArray_Simple() | |
{ | |
var input = "00a0FF00"; | |
var result = ConvertEx.HexadecimalStringToByteArray(input); | |
result.ShouldNotBeNull(); | |
result.Length.ShouldEqual(4); | |
result.SequenceEqual(new byte[] { 0x00, 0xa0, 0xff, 0x00, }); | |
} | |
[TestMethod] | |
public void HexadecimalStringToByteArray_Skips() | |
{ | |
var input = "00 a0 FF 00\r\n00 a0 FF 00"; | |
var result = ConvertEx.HexadecimalStringToByteArray(input); | |
result.ShouldNotBeNull(); | |
result.Length.ShouldEqual(8); | |
result.SequenceEqual(new byte[] { 0x00, 0xa0, 0xff, 0x00, 0x00, 0xa0, 0xff, 0x00, }); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Inspired from https://stackoverflow.com/questions/321370/how-can-i-convert-a-hex-string-to-a-byte-array
Associated answer: https://stackoverflow.com/a/56378760/282105