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

39

希望这不是一个太蠢的问题,我在谷歌搜索了5页但还是没有找到任何相关内容。

我需要做的是将一个包含所有十六进制字符的字符串转换为ASCII码,例如

String fileName = 

75546f7272656e745c436f6d706c657465645c6e667375635f6f73745f62795f6d757374616e675c50656e64756c756d2d392c303030204d696c65732e6d7033006d7033006d7033004472756d202620426173730050656e64756c756d00496e2053696c69636f00496e2053696c69636f2a3b2a0050656e64756c756d0050656e64756c756d496e2053696c69636f303038004472756d2026204261737350656e64756c756d496e2053696c69636f30303800392c303030204d696c6573203c4d757374616e673e50656e64756c756d496e2053696c69636f3030380050656e64756c756d50656e64756c756d496e2053696c69636f303038004d50330000

我看到的所有方法都好像需要先将它们放入一个数组中。有没有办法循环遍历每两个值并进行转换?

7个回答

103

只需使用for循环遍历字符串中的每一对字符,将它们转换为字符,然后将字符添加到一个字符串构建器的末尾即可:

String hex = "75546f7272656e745c436f6d706c657465645c6e667375635f6f73745f62795f6d757374616e675c50656e64756c756d2d392c303030204d696c65732e6d7033006d7033006d7033004472756d202620426173730050656e64756c756d00496e2053696c69636f00496e2053696c69636f2a3b2a0050656e64756c756d0050656e64756c756d496e2053696c69636f303038004472756d2026204261737350656e64756c756d496e2053696c69636f30303800392c303030204d696c6573203c4d757374616e673e50656e64756c756d496e2053696c69636f3030380050656e64756c756d50656e64756c756d496e2053696c69636f303038004d50330000";
StringBuilder output = new StringBuilder();
for (int i = 0; i < hex.length(); i+=2) {
    String str = hex.substring(i, i+2);
    output.append((char)Integer.parseInt(str, 16));
}
System.out.println(output);

或者(Java 8+),如果你感觉特别粗鲁,可以使用臭名昭著的“固定宽度字符串拆分”hack来使您能够使用流进行单行操作:

System.out.println(Arrays
        .stream(hex.split("(?<=\\G..)")) //https://dev59.com/S3E95IYBdhLWcg3wd9xK
        .map(s -> Character.toString((char)Integer.parseInt(s, 16)))
        .collect(Collectors.joining()));

无论如何,这会提供几行以以下内容开头的内容:

uTorrent\Completed\nfsuc_ost_by_mustang\Pendulum-9,000 Miles.mp3

嗯... :-)


97
这个问题获得了“年度最具自证问题”奖项。 - Cory Klein
4
哈哈,说得好,但幸运的是这个文件来自一个曾经处理过的案件,所以我是安全的,但我没有想到哈哈!不过让我笑了 :) - James
1
谢谢“berry120”帮了我很多! :) - James
鉴于字符串的大小事先已知,可以优化 StringBuilder 以容纳所有内容,甚至只使用 char[]。当然,这仅在经常运行时才相关。 - entonio
5
我知道这是一个老问题,但只是提供信息,Guava 14引入了BaseEncoding类,可以像这样使用:new String(BaseEncoding.base16().lowerCase().decode(hex), Charsets.US_ASCII) - BaseEncoding实例可以缓存,因为它是不可变的。 - Matt

12

使用 javax.xml.bind.DatatypeConverter 最简单的方法是:

    String hex = "75546f7272656e745c436f6d706c657465645c6e667375635f6f73745f62795f6d757374616e675c50656e64756c756d2d392c303030204d696c65732e6d7033006d7033006d7033004472756d202620426173730050656e64756c756d00496e2053696c69636f00496e2053696c69636f2a3b2a0050656e64756c756d0050656e64756c756d496e2053696c69636f303038004472756d2026204261737350656e64756c756d496e2053696c69636f30303800392c303030204d696c6573203c4d757374616e673e50656e64756c756d496e2053696c69636f3030380050656e64756c756d50656e64756c756d496e2053696c69636f303038004d50330000";
    byte[] s = DatatypeConverter.parseHexBinary(hex);
    System.out.println(new String(s));

2
这个解决方案给出了与被接受的答案相同的结果。 - LeHill
在我的情况下,字符串以0x开头,我收到了一个异常,抱怨非法字符(在这种情况下是x),所以我只需要做一个substring(2)来排除它们。 ^_^ - Ted Delezene
我得到了不同的输出,我不知道出了什么问题。 字符串:B54075546f7272656e745c436f6d706c657465645c6e667375635f6f73745f62795f6d757374616e675c50656e64756c75 没有使用DatatypeConverter: µ@uTorrent\Completed\nfsuc_ost_by_mustang\Pendulu 使用DatatypeConverter: �@uTorrent\Completed\nfsuc_ost_by_mustang\Pendulu - arjuncc

3
String hexToAscii(String s) {
  int n = s.length();
  StringBuilder sb = new StringBuilder(n / 2);
  for (int i = 0; i < n; i += 2) {
    char a = s.charAt(i);
    char b = s.charAt(i + 1);
    sb.append((char) ((hexToInt(a) << 4) | hexToInt(b)));
  }
  return sb.toString();
}

private static int hexToInt(char ch) {
  if ('a' <= ch && ch <= 'f') { return ch - 'a' + 10; }
  if ('A' <= ch && ch <= 'F') { return ch - 'A' + 10; }
  if ('0' <= ch && ch <= '9') { return ch - '0'; }
  throw new IllegalArgumentException(String.valueOf(ch));
}

2

据我理解,您需要提取连续的十六进制数字对,然后解码这个2位十六进制数并取相应的字符:

String s = "...";
StringBuilder sb = new StringBuilder(s.length() / 2);
for (int i = 0; i < s.length(); i+=2) {
    String hex = "" + s.charAt(i) + s.charAt(i+1);
    int ival = Integer.parseInt(hex, 16);
    sb.append((char) ival);
}
String string = sb.toString();

2

1
//%%%%%%%%%%%%%%%%%%%%%% HEX to ASCII %%%%%%%%%%%%%%%%%%%%%%
public String convertHexToString(String hex){

 String ascii="";
 String str;

 // Convert hex string to "even" length
 int rmd,length;
 length=hex.length();
 rmd =length % 2;
 if(rmd==1)
 hex = "0"+hex;

  // split into two characters
  for( int i=0; i<hex.length()-1; i+=2 ){

      //split the hex into pairs
      String pair = hex.substring(i, (i + 2));
      //convert hex to decimal
      int dec = Integer.parseInt(pair, 16);
      str=CheckCode(dec);
      ascii=ascii+" "+str;
  }
  return ascii;
}

public String CheckCode(int dec){
  String str;

          //convert the decimal to character
        str = Character.toString((char) dec);

      if(dec<32 || dec>126 && dec<161)
             str="n/a";  
  return str;
}

0
在这种情况下,我有一个十六进制数据格式转换成int数组,我想将它们转换为字符串。
int[] encodeHex = new int[] { 0x48, 0x65, 0x6c, 0x6c, 0x6f }; // Hello encode
for (int i = 0; i < encodeHex.length; i++) {
   System.out.print((char) (encodeHex[i]));
}

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