К сожалению, использование BigInteger
завершается неудачно, когда есть начальные нулевые байты.
Я думаю, что ваш оригинальный подход - хорошее начало.Я сделал несколько настроек:
@NotNull
public static byte[] hexToBytes(@NotNull String hex)
{
return hexToBytes(hex.toCharArray());
}
@NotNull
public static byte[] hexToBytes(@NotNull char[] hex)
{
if (hex.length % 2 != 0)
throw new IllegalArgumentException("Must pass an even number of characters.");
int length = hex.length >> 1;
byte[] raw = new byte[length];
for (int o = 0, i = 0; o < length; o++) {
raw[o] = (byte) ((getHexCharValue(hex[i++]) << 4)
| getHexCharValue(hex[i++]));
}
return raw;
}
public static byte getHexCharValue(char c)
{
if (c >= '0' && c <= '9')
return (byte) (c - '0');
if (c >= 'A' && c <= 'F')
return (byte) (10 + c - 'A');
if (c >= 'a' && c <= 'f')
return (byte) (10 + c - 'a');
throw new IllegalArgumentException("Invalid hex character");
}
Обратите внимание, что Character.digit
доступен только в Java 7, и он не проверяет, что указанный символ находится в ожидаемом диапазоне.Мне нравится генерировать исключения, когда входные данные не соответствуют моим ожиданиям, поэтому я добавил это.
Вот несколько базовых модульных тестов:
@Test
public void hexToBytes()
{
assertArrayEquals(new byte[]{0x00, 0x01, 0x02}, Convert.hexToBytes("000102"));
assertArrayEquals(new byte[]{(byte) 0xFF, (byte) 0xFE, (byte) 0xFD}, Convert.hexToBytes("FFFEFD"));
assertArrayEquals(new byte[]{(byte) 0xFF}, Convert.hexToBytes("FF"));
assertArrayEquals(new byte[]{(byte) 0x00}, Convert.hexToBytes("00"));
assertArrayEquals(new byte[]{(byte) 0x01}, Convert.hexToBytes("01"));
assertArrayEquals(new byte[]{(byte) 0x7F}, Convert.hexToBytes("7F"));
assertArrayEquals(new byte[]{(byte) 0x80}, Convert.hexToBytes("80"));
}
@Test(expected = IllegalArgumentException.class)
public void hexToBytesThrowsIfOddNumberOfCharacters()
{
Convert.hexToBytes("12345"); // Odd number of characters
}
@Test(expected = IllegalArgumentException.class)
public void hexToBytesThrowsIfInvalidCharacters()
{
Convert.hexToBytes("ABCDEFGH"); // G and H are invalid in base 16
}
@Test
public void getHexCharValue()
{
assertEquals(0x0, Convert.getHexCharValue('0'));
assertEquals(0x1, Convert.getHexCharValue('1'));
assertEquals(0x9, Convert.getHexCharValue('9'));
assertEquals(0xa, Convert.getHexCharValue('A'));
assertEquals(0xf, Convert.getHexCharValue('F'));
assertEquals(0xa, Convert.getHexCharValue('a'));
assertEquals(0xf, Convert.getHexCharValue('f'));
}
@Test(expected = IllegalArgumentException.class)
public void getHexCharValueThrowsIfInvalid1()
{
Convert.getHexCharValue('z');
}