在Java中将字符串转换为十六进制

123

我正在尝试将类似于"testing123"的字符串在Java中转换为十六进制形式。我目前使用的是BlueJ。

将其转换回来是否也是一样的,只不过是反向操作?

23个回答

225

这是一个简单的将其转换为十六进制的方法:

public String toHex(String arg) {
    return String.format("%040x", new BigInteger(1, arg.getBytes(/*YOUR_CHARSET?*/)));
}

29
这是我曾经见过的最纯粹的邪恶样本+1:使用BigInteger来从byte[]转换... - Eduardo Costa
16
太喜欢了!没有循环和位翻转。我想给你0xFF个赞 :) - laher
5
为确保40个字符,您应该添加零填充:返回String.format("%040x", new BigInteger(arg.getBytes(/YOUR_CHARSET?/))); - Ron
6
@Kaleb,你有没有想过将结果字符串转换回去的可能性?如果可以的话,能否给我一些提示?谢谢! - artaxerxe
2
你必须使用 BigInteger(int,byte[]) 构造函数;否则,如果第一个字节为负数,则会得到一个负的 BigInteger。 - Joni
显示剩余6条评论

68
为了确保十六进制始终有40个字符长度,BigInteger必须为正数:
public String toHex(String arg) {
  return String.format("%x", new BigInteger(1, arg.getBytes(/*YOUR_CHARSET?*/)));
}

1
这个方法其实是正确的。尝试使用 byte[] data = { -1, 1 }; -- 这个答案中的代码可以正常工作,而那个得到17个赞的则失败了。 - hudolejev
1
在字符串中获取值为“-1”的字节(如示例中所请求)是否是可能的? - Kaleb Pederson
@KalebPederson 是的。这甚至不难。 如果您选择的编码_曾经_使用任何字符的最高有效位(比如UTF-*),则数组中会有负byte - anon

57

4
有趣的是,如果你不想重新发明轮子。 - Federico Zancan
3
@MelNicholson 在 Hex 中有一个 decodeHex 函数可以将 HEX 转换为 byte[]。你需要使用它,因为没有任何保证随机的 HEX 字符串可以转换为你所用编码的字符串。 - BxlSofty

22

使用DatatypeConverter.printHexBinary()函数:

public static String toHexadecimal(String text) throws UnsupportedEncodingException
{
    byte[] myBytes = text.getBytes("UTF-8");

    return DatatypeConverter.printHexBinary(myBytes);
}

使用示例:

System.out.println(toHexadecimal("Hello StackOverflow"));

输出:

48656C6C6F20537461636B4F766572666C6F77

注意:这个操作在Java 9及更高版本中会导致一些额外的麻烦,因为API默认不包含在内。例如,请参见这个GitHub问题。


21

你将数字编码为十六进制,必须表示某些字符的编码方式,例如UTF-8。因此,首先将字符串转换为byte [],表示该编码中的字符串,然后将每个字节转换为十六进制。

public static String hexadecimal(String input, String charsetName) throws UnsupportedEncodingException {
    if (input == null) throw new NullPointerException();
    return asHex(input.getBytes(charsetName));
}

private static final char[] HEX_CHARS = "0123456789abcdef".toCharArray();

public static String asHex(byte[] buf)
{
    char[] chars = new char[2 * buf.length];
    for (int i = 0; i < buf.length; ++i)
    {
        chars[2 * i] = HEX_CHARS[(buf[i] & 0xF0) >>> 4];
        chars[2 * i + 1] = HEX_CHARS[buf[i] & 0x0F];
    }
    return new String(chars);
}

这是一个有趣的解决方案,它触及了数据数字化表示的核心。不过,您能否解释一下您正在做什么,以及您解决方案中的“魔数”代表什么?新手可能不知道 >>> 运算符的含义,为什么我们要使用按位与 & 以及掩码 0xF0,或者为什么 chars 数组的大小为 [2 * buf.length]。 - Boris

15

Java 17引入了一个十六进制格式化的实用类:java.util.HexFormat

转换为十六进制:

public String toHex(String value) {
    return HexFormat.of().formatHex(value.getBytes());
}

十六进制转换:

public String fromHex(String value) {
    return new String(HexFormat.of().parseHex(value));
}

更多关于HexFormat的信息在此处

文档:在此处


12

这里有另外一种解决方案

public static String toHexString(byte[] ba) {
    StringBuilder str = new StringBuilder();
    for(int i = 0; i < ba.length; i++)
        str.append(String.format("%x", ba[i]));
    return str.toString();
}

public static String fromHexString(String hex) {
    StringBuilder str = new StringBuilder();
    for (int i = 0; i < hex.length(); i+=2) {
        str.append((char) Integer.parseInt(hex.substring(i, i + 2), 16));
    }
    return str.toString();
}

3
不错,但我会使用format(“%02x”),这样format()始终使用2个字符。即使ASCII是双位十六进制,即A = 0x65。 - mike jones

8

所有基于String.getBytes()的答案都涉及根据Charset对您的字符串进行编码。您不一定会得到组成字符串的2字节字符的十六进制值。如果您真正想要的是十六进制查看器的等价物,则需要直接访问字符。以下是我在调试Unicode问题时在我的代码中使用的函数:

static String stringToHex(String string) {
  StringBuilder buf = new StringBuilder(200);
  for (char ch: string.toCharArray()) {
    if (buf.length() > 0)
      buf.append(' ');
    buf.append(String.format("%04x", (int) ch));
  }
  return buf.toString();
}

然后,stringToHex("testing123") 将会给你:

0074 0065 0073 0074 0069 006e 0067 0031 0032 0033

1
如果您想查看Java字符的内部表示形式,这很好,它是UTF-16,Unicode的一种特定表示形式。 - Jonathan Rosenne
1
这会打印前导零,即使它们实际上不在内存中。Java不再总是使用UTF-16了。 - Martin

5
我建议像这样做,其中str是您的输入字符串:
StringBuffer hex = new StringBuffer();
char[] raw = tokens[0].toCharArray();
for (int i=0;i<raw.length;i++) {
    if     (raw[i]<=0x000F) { hex.append("000"); }
    else if(raw[i]<=0x00FF) { hex.append("00" ); }
    else if(raw[i]<=0x0FFF) { hex.append("0"  ); }
    hex.append(Integer.toHexString(raw[i]).toUpperCase());
}

感谢您的纠正,Software Monkey。我回答时非常疲倦,我的“raw[i] <= 9”的测试显然是不足的。 - rodion
1
这个很好用,有没有办法将生成的十六进制字符串再转回字符串? - user3025039
1
这里有 str 吗? - Viswanath Lekshmanan

5
byte[] bytes = string.getBytes(CHARSET); // you didn't say what charset you wanted
BigInteger bigInt = new BigInteger(bytes);
String hexString = bigInt.toString(16); // 16 is the radix

现在你可以返回hexString,但请注意,如果第一个字节小于16,则会去掉前导空字符并且结果长度为奇数。如果你需要处理这些情况,你可以添加一些额外的代码来用0填充:

StringBuilder sb = new StringBuilder();
while ((sb.length() + hexString.length()) < (2 * bytes.length)) {
  sb.append("0");
}
sb.append(hexString);
return sb.toString();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接