这是将字符串十六进制转换为字节的最佳方法吗?

发布于 2024-08-28 16:33:52 字数 527 浏览 5 评论 0原文

这是将字符串十六进制转换为字节的最佳方法吗? 或者你能想到更短/更简单的吗?

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

Is this the best way to convert String hex to bytes?
Or can you think a shorter/simpler?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

朮生 2024-09-04 16:33:52
byte[] yourBytes = new BigInteger(hexString, 16).toByteArray();
byte[] yourBytes = new BigInteger(hexString, 16).toByteArray();
时光是把杀猪刀 2024-09-04 16:33:52

当值大于 127 时,不需要减去 256。只需将值转换为字节即可。例如,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;
  }

You don't need the subtraction of 256 when the value is greater than 127. Just cast the value to a byte. For example, byte b = (byte) 255 assigns a value of -1 to b.

A narrowing conversion on integer types simply discards the high-order bits that don't fit in the target type.

  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;
  }
妥活 2024-09-04 16:33:52

不幸的是,当存在前导零字节时,使用 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');
}

Unfortunately, using BigInteger fails when there are leading zero bytes.

I think your original approach is a good start. I made some tweaks:

@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");
}

Note that Character.digit is only available in Java 7, and it doesn't validate that the provided character is within the expected range. I like to throw exceptions when input data doesn't match my expectations, so I've added that.

Here are some basic unit tests:

@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');
}
在你怀里撒娇 2024-09-04 16:33:52

您可以使用 Bouncy Castle Crypto 包 - Java 和密码算法的 C# 实现。

// import org.bouncycastle.util.encoders.Hex;
String msgHex = Hex.toHexString("Ehlo-HEX!".getBytes());
byte[] msgBytes = Hex.decode(msgHex);
System.out.println("hex(" + new String(msgBytes) + ")=" + msgHex);

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.65</version>
</dependency>

You can use the Bouncy Castle Crypto package - Java & C# implementation of cryptographic algorithms.

// import org.bouncycastle.util.encoders.Hex;
String msgHex = Hex.toHexString("Ehlo-HEX!".getBytes());
byte[] msgBytes = Hex.decode(msgHex);
System.out.println("hex(" + new String(msgBytes) + ")=" + msgHex);

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.65</version>
</dependency>
无声情话 2024-09-04 16:33:52

最简单的方法:

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

The easiest way:

private static byte[] hexToBytes(char[] hex)
{
    return DatatypeConverter.parseHexBinary(hex.toString());
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文