我有一个十六进制字符串,我需要转换为字节数组。最好的方法(即有效和最少的代码)是:
string hexstr = "683A2134";
byte[] bytes = new byte[hexstr.Length/2];
for(int x = 0; x < bytes.Length; x++)
{
bytes[x] = Convert.ToByte(hexstr.Substring(x * 2, 2), 16);
}
如果我有32位值,我可以执行以下操作:
string hexstr = "683A2134";
byte[] bytes = BitConverter.GetBytes(Convert.ToInt32(hexstr, 16));
然而,一般情况呢?是否有更好的内置功能,或更清晰(不一定要更快,但仍然高效)的方式吗?
我更喜欢内置函数,因为除了这个特殊的转换之外,似乎有一个(很常见的东西)。
答案 0 :(得分:5)
如果您从字符代码计算值而不是创建子字符串并解析它们,您将获得最佳性能。
C#中的代码,它处理大写和小写十六进制(但没有验证):
static byte[] ParseHexString(string hex) {
byte[] bytes = new byte[hex.Length / 2];
int shift = 4;
int offset = 0;
foreach (char c in hex) {
int b = (c - '0') % 32;
if (b > 9) b -= 7;
bytes[offset] |= (byte)(b << shift);
shift ^= 4;
if (shift != 0) offset++;
}
return bytes;
}
用法:
byte[] bytes = ParseHexString("1fAB44AbcDEf00");
由于代码使用了一些技巧,这里有一个注释版本:
static byte[] ParseHexString(string hex) {
// array to put the result in
byte[] bytes = new byte[hex.Length / 2];
// variable to determine shift of high/low nibble
int shift = 4;
// offset of the current byte in the array
int offset = 0;
// loop the characters in the string
foreach (char c in hex) {
// get character code in range 0-9, 17-22
// the % 32 handles lower case characters
int b = (c - '0') % 32;
// correction for a-f
if (b > 9) b -= 7;
// store nibble (4 bits) in byte array
bytes[offset] |= (byte)(b << shift);
// toggle the shift variable between 0 and 4
shift ^= 4;
// move to next byte
if (shift != 0) offset++;
}
return bytes;
}
答案 1 :(得分:4)
遗憾的是,没有任何内置功能。 (我真的应该得到我在其他地方得到的代码 - 至少是第三次或第四次我写的。)
你当然可以创建一个更高效的版本,它从char中解析出一个nybble,而不是每次都使用一个子字符串,但它的代码更多。如果您经常使用它,请对原始代码进行基准测试,以确定它是否适合首先使用。
private static int ParseNybble(char nybble)
{
// Alternative implementations: use a lookup array
// after doing some bounds checking, or use
// if (nybble >= '0' && nybble <= '9') return nybble-'0' etc
switch (nybble)
{
case '0' : return 0;
case '1' : return 1;
case '2' : return 2;
case '3' : return 3;
case '4' : return 4;
case '5' : return 5;
case '6' : return 6;
case '7' : return 7;
case '8' : return 8;
case '9' : return 9;
case 'a': case 'A' : return 10;
case 'b': case 'B' : return 11;
case 'c': case 'C' : return 12;
case 'd': case 'D' : return 13;
case 'e': case 'E' : return 14;
case 'f': case 'F' : return 15;
default: throw new ArgumentOutOfRangeException();
}
}
public static byte[] ParseHex(string hex)
{
// Do error checking here - hex is null or odd length
byte[] ret = new byte[hex.Length/2];
for (int i=0; i < ret.Length; i++)
{
ret[i] = (byte) ((ParseNybble(hex[i*2]) << 4) |
(ParseNybble(hex[i*2+1])));
}
return ret;
}
答案 2 :(得分:3)
看看这个 - 它非常简短,是.NET框架的一部分:
System.Runtime.Remoting.Metadata.W3cXsd2001.SoapHexBinary.Parse("C3B01051359947").Value
答案 3 :(得分:0)
public class HexCodec {
private static final char[] kDigits =
{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f' };
public static byte[] HexToBytes(char[] hex) {
int length = hex.length / 2;
byte[] raw = new byte[length];
for (int i = 0; i < length; i++) {
int high = Character.digit(hex[i * 2], 16);
int low = Character.digit(hex[i * 2 + 1], 16);
int value = (high << 4) | low;
if (value > 127)
value -= 256;
raw[i] = (byte) value;
}
return raw;
}
public static byte[] HexToBytes(String hex) {
return hexToBytes(hex.toCharArray());
}
}
答案 4 :(得分:0)
这是使用LINQ的单线程。它基本上只是原始版本的翻译:
string hexstr = "683A2134";
byte[] bytes = Enumerable.Range(0, hexstr.Length / 2)
.Select((x, i) => Convert.ToByte(hexstr.Substring(i * 2, 2), 16))
.ToArray();
如果您可能需要转换长度不均匀的字符串(即,如果它们可能具有隐式前导零),则代码会变得更复杂:
string hexstr = "683A2134F"; // should be treated as "0683A2134F"
byte[] bytes = Enumerable.Range(0, (hexstr.Length / 2) + (hexstr.Length & 1))
.Select((x, i) => Convert.ToByte(hexstr.Substring((i * 2) - (i == 0 ? 0 : hexstr.Length & 1), 2 - (i == 0 ? hexstr.Length & 1 : 0)), 16))
.ToArray();