Это лучший способ преобразовать шестнадцатеричные строки в байты? - PullRequest
1 голос
/ 15 апреля 2010

Является ли это наилучшим способом преобразования шестнадцатеричных строк в байты? Или вы можете думать короче / проще?

public static byte[] hexToBytes(String hex) {
return hexToBytes(hex.toCharArray());
}

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;
}

Ответы [ 4 ]

4 голосов
/ 15 апреля 2010
byte[] yourBytes = new BigInteger(hexString, 16).toByteArray();
2 голосов
/ 15 апреля 2010

Вам не нужно вычитать 256, когда значение больше 127. Просто приведите значение к байту. Например, byte b = (byte) 255 присваивает значение от -1 до b.

При сужающемся преобразовании целочисленных типов просто отбрасываются старшие биты, которые не вписываются в целевой тип.

  private static byte[] hexToBytes(char[] hex)
  {
    byte[] raw = new byte[hex.length / 2];
    for (int src = 0, dst = 0; dst < raw.length; ++dst) {
      int hi = Character.digit(hex[src++], 16);
      int lo = Character.digit(hex[src++], 16);
      if ((hi < 0) || (lo < 0))
        throw new IllegalArgumentException();
      raw[dst] = (byte) (hi << 4 | lo);
    }
    return raw;
  }
1 голос
/ 13 февраля 2013

К сожалению, использование 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');
}
0 голосов
/ 17 августа 2016

Самый простой способ:

private static byte[] hexToBytes(char[] hex)
{
    return DatatypeConverter.parseHexBinary(hex.toString());
}
...